diff --git a/CMakeLists.txt b/CMakeLists.txt index c5c468a..0f9e7f3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,12 +3,19 @@ Project(Stasis) SET(PACKAGE_VERSION 1) SUBDIRS(src test utilities benchmarks examples) +SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +SET(FLEX_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmake) +SET(BISON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cmake) # Main decisions SET(BUILD_SHARED_LIBS ON) #ENABLE_TESTING() INCLUDE(CTest) +FIND_PACKAGE(FLEX) +FIND_PACKAGE(BISON) + + # Look for include files INCLUDE (CheckIncludeFiles) FIND_LIBRARY(CHECK_LIBRARY NAMES check) diff --git a/src/apps/referential/CMakeLists.txt b/src/apps/referential/CMakeLists.txt index 120498e..6c3687d 100644 --- a/src/apps/referential/CMakeLists.txt +++ b/src/apps/referential/CMakeLists.txt @@ -1,5 +1,6 @@ -ADD_LIBRARY(referential algebra.c dml.c) -SET(COMMON_LIBRARIES referential ${COMMON_LIBRARIES}) +SUBDIRS(lang) +ADD_LIBRARY(referential algebra.c dml.c ddl.c tuple.c lang/ast.c) +SET(COMMON_LIBRARIES referential refparse ${COMMON_LIBRARIES}) IF(CHECK_LIBRARY) CREATE_CHECK_OPT(toplevel ${CMAKE_CURRENT_SOURCE_DIR}/test-script.ref) ENDIF(CHECK_LIBRARY) diff --git a/src/apps/referential/algebra.c b/src/apps/referential/algebra.c index 22867d0..f76648d 100644 --- a/src/apps/referential/algebra.c +++ b/src/apps/referential/algebra.c @@ -4,38 +4,15 @@ #include #include #include "algebra.h" +//#include "old_algebra.h" +#include "lang/ast.h" #include #include #define SELECT_ITERATOR (USER_DEFINED_ITERATOR+1) #define PROJECT_ITERATOR (USER_DEFINED_ITERATOR+2) #define KEYVAL_ITERATOR (USER_DEFINED_ITERATOR+3) #define JOIN_ITERATOR (USER_DEFINED_ITERATOR+4) - -/* static void ts_close(int xid, void * it) { - -} -static int ts_next(int xid, void * it) { - -} -static int ts_tryNext(int xid, void * it) { - -} -static int ts_key(int xid, void * it, byte ** key) { - -} -static int ts_value(int xid, void * it, byte ** val) { - -} -static void ts_tupleDone(int xid, void * it) { - -} -static void ts_releaseLock(int xid, void *it) { - -} */ -/*static const lladdIterator_def_t ts_it = { - ts_close, ts_next, ts_tnext, ts_key, ts_value, ts_tupleDone, noopTupDone - }; */ - +#define KEYVALTUP_ITERATOR (USER_DEFINED_ITERATOR+3) char ** split(char * in, char ** freeme, int* count, char * delim) { *freeme = strdup(in); @@ -54,48 +31,6 @@ char ** split(char * in, char ** freeme, int* count, char * delim) { return ret; } -char * tplRid(recordid rid) { - char * ret; - asprintf(&ret, "%lld,%lld,%lld", (long long)rid.page, (long long)rid.slot, (long long)rid.size); - return ret; -} -recordid ridTpl(char * tpl) { - int count; - char * freeme; - char ** tok = split(tpl, &freeme, &count, ", "); - recordid ret; - errno = 0; - assert(count == 3); - ret.page = strtol(tok[0],NULL,10); - ret.slot = strtol(tok[1],NULL,10); - ret.size = strtol(tok[2],NULL,10); - if(errno) { - perror("Couldn't parse rid"); - abort(); - } - free(freeme); - free(tok); - return ret; -} - -char ** tplDup(char ** tup) { - int i = 0; - for(; tup[i]; i++) { } // i = num non-null entries - char ** ret = malloc(sizeof(char**) * (i+1)); - ret[i] = 0; - while(i) { - i--; - ret[i] = strdup(tup[i]); - } - return ret; -} -void tplFree(char ** tup) { - for(int i = 0; tup[i]; i++) { - free(tup[i]); - } - free(tup); -} - int isWhitelistChar(char c) { return(c == ';' || @@ -138,17 +73,56 @@ int isWhitelistChar(char c) { c == '\\'); } + + +/* static void ts_close(int xid, void * it) { + +} +static int ts_next(int xid, void * it) { + +} +static int ts_tryNext(int xid, void * it) { + +} +static int ts_key(int xid, void * it, byte ** key) { + +} +static int ts_value(int xid, void * it, byte ** val) { + +} +static void ts_tupleDone(int xid, void * it) { + +} +static void ts_releaseLock(int xid, void *it) { + +} */ +/*static const lladdIterator_def_t ts_it = { + ts_close, ts_next, ts_tnext, ts_key, ts_value, ts_tupleDone, noopTupDone + }; */ + + +static lladdIterator_t* ReferentialAlgebra_KeyValTupIterator(int xid, lladdIterator_t * it, datatype_t typ); + lladdIterator_t* ReferentialAlgebra_OpenTableScanner(int xid, recordid catalog, char * tablename) { - char * table; + byte * table; size_t sz = ThashLookup(xid, catalog, (byte*)tablename, strlen(tablename)+1, (byte**)&table); if(sz == -1) { printf("Unknown table %s\n", tablename); return 0; } - assert(sz == strlen(table)+1); - recordid tableRid = ridTpl(table); - lladdIterator_t * it = ThashGenericIterator(xid, tableRid); + // assert(sz == strlen(table)+1); + /*recordid tableRid = ridTpl(table); */ + tuple_t tpl = tupleByte(table); + recordid tableRid = ridTuple(tpl); + + assert(tpl.count >=4); + assert(tpl.type[3] == int64_typ); + + // XXX assumes first column is a string + lladdIterator_t * it = ReferentialAlgebra_KeyValTupIterator(xid, ThashGenericIterator(xid, tableRid), tpl.col[3].int64); + + tupleFree(tpl); free(table); return it; } @@ -160,7 +134,7 @@ typedef struct select_predicate { typedef struct select_impl { lladdIterator_t * it; - char ** p; + union_cmp * p; } select_impl; ////////////////////////////////////////////////////////////////////////////////// @@ -169,6 +143,92 @@ typedef struct select_impl { /// /// ////////////////////////////////////////////////////////////////////////////////// +typedef struct kvt_impl { + datatype_t keytype; + tuple_t t; + lladdIterator_t * it; +} kvt_impl; + +static lladdIterator_t* ReferentialAlgebra_KeyValTupIterator(int xid, lladdIterator_t * it, datatype_t typ) { + kvt_impl * kvt = malloc(sizeof(kvt_impl)); + kvt->keytype = typ; + kvt->t = tupleAlloc(); + kvt->it = it; + lladdIterator_t * new_it = malloc(sizeof(lladdIterator_t)); + new_it->type = KEYVALTUP_ITERATOR; + new_it->impl = kvt; + return new_it; +} + +static void kvt_close(int xid, void * it) { + kvt_impl * kvt = it; + Titerator_close(xid, kvt->it); + tupleFree(kvt->t); + free(kvt); +} +static int mkKvtTuple(int xid, kvt_impl * kvt) { + byte * keybytes; + byte * valbytes; + Titerator_key(xid,kvt->it,&keybytes); + Titerator_value(xid,kvt->it,&valbytes); + kvt->t = tupleAlloc(); + if(kvt->keytype == string_typ) { + kvt->t = tupleCatString(kvt->t, (char*)keybytes); + } else if(kvt->keytype == int64_typ) { + kvt->t = tupleCatInt64(kvt->t, *(int64_t*)keybytes); + } else { + abort(); + } + tuple_t valtuple = tupleByte(valbytes); + kvt->t = tupleCatTuple(kvt->t, valtuple); + tupleFree(valtuple); + return 1; +} + +static int kvt_next(int xid, void * it) { + kvt_impl * kvt = it; + int ret; + if((ret=Titerator_next(xid, kvt->it))) { + tupleFree(kvt->t); + mkKvtTuple(xid, kvt); + } + return ret; +} +static int kvt_tryNext(int xid, void * it) { + kvt_impl * kvt = it; + // if(kv->catted) { free(kv->catted); kv->catted = 0; } + int ret; + if((ret = Titerator_tryNext(xid, kvt->it))) { + tupleFree(kvt->t); + mkKvtTuple(xid,kvt); + } + return ret; +} +static int kvt_key(int xid, void * it, byte ** key) { + kvt_impl * kvt = it; + *key = (byte*)&kvt->t; + return 1; +} +static int kvt_value(int xid, void * it, byte ** val) { + kvt_impl * kvt = it; + *val = (byte*)&kvt->t; + return 1; +} +static void kvt_tupleDone(int xid, void * it) { + kvt_impl * kvt = it; + Titerator_tupleDone(xid, kvt->it); +} +static void kvt_releaseLock(int xid, void *it) { + kvt_impl * kvt = it; + Titerator_releaseLock(xid, kvt->it); +} + +////////////////////////////////////////////////////////////////////////////////// +/// /// +/// KEY VALUE TABLE FORMAT (obsolete version) /// +/// /// +////////////////////////////////////////////////////////////////////////////////// + typedef struct kv_impl { char * catted; lladdIterator_t * it; @@ -201,17 +261,17 @@ static int kv_tryNext(int xid, void * it) { return Titerator_tryNext(xid, kv->it); } static int mkCatted(int xid, kv_impl * kv) { - char * key = 0; - char * val = 0; + byte * key = 0; + byte * val = 0; Titerator_key(xid, kv->it, (byte**)&key); Titerator_value(xid, kv->it, (byte**)&val); - if(!strlen(val)) { - kv->catted = strdup(key); + if(!strlen((char*)val)) { + kv->catted = strdup((char*)key); } else { - kv->catted = malloc(strlen(key) + 1 + strlen(val) + 1); + kv->catted = malloc(strlen((char*)key) + 1 + strlen((char*)val) + 1); kv->catted[0]=0; - strcat(strcat(strcat(kv->catted,key),","),val); + strcat(strcat(strcat(kv->catted,(char*)key),","),(char*)val); } return(strlen(kv->catted)); } @@ -251,11 +311,8 @@ static void kv_releaseLock(int xid, void *it) { /// SELECT /// /// /// ////////////////////////////////////////////////////////////////////////////////// -lladdIterator_t* ReferentialAlgebra_Select(int xid, lladdIterator_t * it, char ** pred) { - if(!it) { - tplFree(pred); - return 0; - } +lladdIterator_t* ReferentialAlgebra_Select(int xid, lladdIterator_t * it, union_cmp * pred) { + if(!it) return 0; select_impl * s = malloc(sizeof(select_impl)); s->p = pred; s->it = it; @@ -300,64 +357,110 @@ char * strtokempt(char *str, const char * delim, char ** saveptr, int * extra) { return ret; } -static int matchPredicate(const char const * tup, char ** pred) { - char * tupcpy = strdup(tup); - int colcount = 0; - int predcount = 0; - while(pred[predcount]) {predcount++;} - char ** tok = malloc((predcount+1) * sizeof(char**)); +static int matchUnionCmp(tuple_t tup, union_cmp * cmp) { + assert(cmp->count == 1); // not implmented - char * ths; - const char const * DELIM = ","; - char * strtoks; - int extra = 0; - if((ths = strtokempt(tupcpy, DELIM,&strtoks,&extra))) { - colcount++; - if(colcount > predcount) { - free(tupcpy); - free(tok); - return 0; - } else { - tok[colcount-1] = ths; - } - } - while((ths = strtokempt(NULL, DELIM,&strtoks,&extra))) { - colcount++; - if(colcount > predcount) { - free(tupcpy); - free(tok); - return 0; - } else { - tok[colcount-1] = ths; - } - } - int match = 0; - if(colcount == predcount) { - match=1; - for(int i = 0; i < predcount; i++) { - if(strcmp(pred[i],"*") && strcmp(pred[i], tok[i])) { - match = 0; - break; + for(col_t i = 0; i < cmp->ents[0]->count; i++) { + assert(cmp->ents[0]->ents[i]->comparator == equal_typ); // XXX + enum cmp_side_typ l = cmp->ents[0]->ents[i]->lhs_typ; + enum cmp_side_typ r = cmp->ents[0]->ents[i]->rhs_typ; + + if(l == col_typ && r == val_typ) { + col_entry * lc = cmp->ents[0]->ents[i]->lhs.colent; + val_entry * rv = cmp->ents[0]->ents[i]->rhs.valent; + + assert(lc->typ == colint_typ); //XXX colstr_typ unimplemented + + // (0) Does the column exist? + if(tup.count <= lc->u.colnum) { printf("XXX tuple is too short\n"); return 0; } + // (1) No type coercion. + if(tup.type[lc->u.colnum] != rv->typ) { return 0; } + + // (2) Enumerate over known types + if(rv->typ == int64_typ) { + if(tup.col[lc->u.colnum].int64 != rv->u.integ) { return 0; } + } else if(rv->typ == string_typ) { + if(strcmp(tup.col[lc->u.colnum].string, rv->u.str)) { return 0; } + } else { + abort(); } + } else if (l == val_typ && r == col_typ) { + col_entry * rc = cmp->ents[0]->ents[i]->rhs.colent; + val_entry * lv = cmp->ents[0]->ents[i]->lhs.valent; + + assert(rc->typ == colint_typ); //XXX colstr_typ unimplemented + + // (0) Does the column exist? + if(tup.count <= rc->u.colnum) { printf("XXX tuple is too short\n"); return 0; } + + // (1) No type coercion. + if(tup.type[rc->u.colnum] != lv->typ) { return 0; } + + // (2) Enumerate over known types + if(lv->typ == int64_typ) { + if(tup.col[rc->u.colnum].int64 != lv->u.integ) { return 0; } + } else if(lv->typ == string_typ) { + if(strcmp(tup.col[rc->u.colnum].string, lv->u.str)) { return 0; } + } else { + abort(); + } + } else if (l == col_typ && r == col_typ) { + col_entry * rc = cmp->ents[0]->ents[i]->rhs.colent; + col_entry * lc = cmp->ents[0]->ents[i]->lhs.colent; + assert(rc->typ == colint_typ); //XXX unimplemented + assert(lc->typ == colint_typ); //XXX unimplemented + + // (0) Do the columns exist? + if(tup.count <= lc->u.colnum || tup.count <= rc->u.colnum) { + printf("XXX tuple is too short\n"); + return 0; + } + + // (1) No type coercion + if(tup.type[rc->u.colnum] != tup.type[lc->u.colnum]) { return 0; } + + // (2) Enumerate over types + if(tup.type[rc->u.colnum] == int64_typ) { + if(tup.col[rc->u.colnum].int64 != tup.col[lc->u.colnum].int64) { return 0; } + } else if(tup.type[rc->u.colnum] == string_typ) { + if(strcmp(tup.col[rc->u.colnum].string, tup.col[lc->u.colnum].string)) { return 0; } + } else { + abort(); + } + } else if (l == val_typ && r == val_typ) { + val_entry * rv = cmp->ents[0]->ents[i]->rhs.valent; + val_entry * lv = cmp->ents[0]->ents[i]->lhs.valent; + // (0) Don't need length check; not examining tuple + // (1) No type coercion. + if(rv->typ != lv->typ) { return 0; } + // (2) Enumerate over types + if(rv->typ == int64_typ) { + if(rv->u.integ != lv->u.integ) { return 0; } + } else if(rv->typ == string_typ) { + if(strcmp(rv->u.str, lv->u.str)) { return 0; } + } else { + abort(); + } + } else { + abort(); } } - free(tupcpy); - free(tok); - return match; + return 1; } + static void s_close(int xid, void * it) { select_impl * impl = it; Titerator_close(xid, impl->it); - tplFree(impl->p); + //tplFree(impl->p); free(impl); } static int s_next(int xid, void * it) { select_impl * impl = it; while(Titerator_next(xid,impl->it)) { - char * val; - Titerator_value(xid, impl->it, (byte**)&val); + byte* val; + Titerator_value(xid, impl->it, &val); // printf("matching w/ %s\n", val); - if(matchPredicate(val, impl->p)) { + if(matchUnionCmp(*(tuple_t*)val, impl->p)) { return 1; } else { Titerator_tupleDone(xid, impl->it); @@ -391,99 +494,74 @@ typedef struct project_impl { int count; short * cols; lladdIterator_t * it; - char * val; + tuple_t tup; + int haveTup; } project_impl; -lladdIterator_t* ReferentialAlgebra_Project(int xid, lladdIterator_t * it, char ** project) { - if(!it) { - if(project) { - tplFree(project); - } - return 0; - } +lladdIterator_t* ReferentialAlgebra_Project(int xid, lladdIterator_t * it, col_tuple * project) { + if(!it) return 0; project_impl * p = malloc(sizeof(project_impl)); - int projectcount = 0; - while(project[projectcount]){projectcount++;} - p->count = projectcount; - p->cols = malloc(sizeof(short) * projectcount); + p->count = project->count; + p->cols = malloc(sizeof(short) * p->count); p->it = it; - p->val = 0; - for(int i = 0; project[i]; i++) { + p->haveTup = 0; + for(int i = 0; i < p->count; i++) { errno = 0; - char * eos; - long col = strtol(project[i], &eos, 10); - if(*eos!='\0' || ((col == LONG_MIN || col == LONG_MAX) && errno)) { - printf("Couldn't parse column descriptor\n"); - tplFree(project); - free(p->cols); - free(p); - return 0; - } else { - p->cols[i] = col; - } + assert(project->ents[i]->typ == colint_typ); // XXX + p->cols[i] = project->ents[i]->u.colnum; } lladdIterator_t * new_it = malloc(sizeof(lladdIterator_t)); new_it->type = PROJECT_ITERATOR; new_it->impl = p; - tplFree(project); return new_it; } static void p_close(int xid, void * it) { project_impl * impl = it; Titerator_close(xid, impl->it); + if(impl->haveTup) { tupleFree(impl->tup); } free(impl->cols); free(impl); } static int p_next(int xid, void * it) { project_impl * impl = it; + if(impl->haveTup) { + tupleFree(impl->tup); + impl->haveTup = 0; + } return Titerator_next(xid, impl->it); + } static int p_tryNext(int xid, void * it) { project_impl * impl = it; + abort(); return Titerator_tryNext(xid, impl->it); } +static int p_value(int xid, void * it, byte ** val) ; static int p_key(int xid, void * it, byte ** key) { - project_impl * impl = it; - return Titerator_key(xid,impl->it,key); + return p_value(xid, it, key); } static int p_value(int xid, void * it, byte ** val) { project_impl * impl = it; byte * in_val; - if(impl->val) { - *val = (byte*)impl->val; + if(impl->haveTup) { + *val = (byte*)&(impl->tup); return 1; } int ret = Titerator_value(xid,impl->it,&in_val); if(ret) { - char * freeme; - int count; - char ** tok = split((char*)in_val, &freeme, &count, ", "); - *val = malloc(sizeof(char)); - (*val)[0] = '\0'; - - for(int i = 0; i < impl->count; i++) { - if(impl->cols[i] < count) { - if(i) { - (*val) = realloc((*val), strlen((char*)(*val)) + 1 + strlen(tok[impl->cols[i]]) + 1); - (*val) = (byte*)strcat(strcat((char*)(*val), ","), tok[impl->cols[i]]); - } else { - (*val) = realloc((*val), strlen((char*)(*val)) + strlen(tok[impl->cols[i]]) + 1); - (*val) = (byte*)strcat((char*)(*val), tok[impl->cols[i]]); - } - } else { - printf("Tuple is too short for pattern.\n"); - } + impl->tup = tupleAlloc(); + for(col_t i = 0; i < impl->count; i++) { + impl->tup = tupleCatCol(impl->tup, *(tuple_t*)in_val, impl->cols[i]); } - free(freeme); - free(tok); + impl->haveTup = 1; + *val = (byte*)&(impl->tup); } - impl->val = (char*)*val; return ret; } static void p_tupleDone(int xid, void * it) { project_impl * impl = it; - if(impl->val) { free(impl->val); impl->val = 0; } + if(impl->haveTup) { tupleFree(impl->tup); impl->haveTup = 0; } Titerator_tupleDone(xid,impl->it); } static void p_releaseLock(int xid, void *it) { @@ -498,80 +576,118 @@ static void p_releaseLock(int xid, void *it) { ////////////////////////////////////////////////////////////////////////////////// typedef struct join_impl { - char *** inner_tpls; - char ** inner_strs; - char ** freethese; + tuple_t * inner_tpls; + uint64_t inner_count; lladdIterator_t * outer_it; lladdIterator_t * inner_it; - char ** pred; - int inner_pos; - char ** outer_tpl; - char * outer_str; - char * freeouter; + cmp_tuple * pred; + uint64_t inner_pos; + int have_outer; + tuple_t outer_tpl; + tuple_t t; } join_impl; -static int matchComparator(char ** tup1, - char ** tup2, - char ** pred) { - int match = 1; - int col = 0; - while(pred[col] && match) { - char * lhs_start = pred[col]; - char * lhs_end = lhs_start; - while(isWhitelistChar(*lhs_end)||isalnum(*lhs_end)) { lhs_end++; } - int lhs_len = lhs_end - lhs_start; +// return the value of a column, given a tuple and cmp->lhs_typ, cmp->lhs +static int resolveColName(/*OUT*/val_col_int *colnum, datatype_t * datatype, int64_t *val_int64, char **val_string, + /*IN*/ tuple_t tup, enum cmp_side_typ cmp_typ, col_entry * colent, val_entry * valent) { + //val_col_int colnum; + //datatype_t datatype; + switch(cmp_typ) { + case col_typ: { + datatype_t lhs_colreftype = colent->typ; - char * lhs = calloc(lhs_len+1,sizeof(char)); - memcpy(lhs, lhs_start, lhs_len); - - char * op_start = lhs_end; - while(isblank(*op_start)) { op_start++; } - char * op_end = op_start; - while(!(isblank(*op_end) || isWhitelistChar(*lhs_end)||isalnum(*op_end))) { op_end++; } - int op_len = op_end - op_start; - - char * op = calloc(op_len+1,sizeof(char)); - memcpy(op, op_start, op_len); - - char * rhs_start = op_end; - while(isblank(*rhs_start)) { rhs_start++; } - char * rhs_end = rhs_start; - while(isWhitelistChar(*lhs_end)||isalnum(*rhs_end)) { rhs_end++; } - int rhs_len = rhs_end - rhs_start; - - char * rhs = calloc(rhs_len+1,sizeof(char)); - memcpy(rhs, rhs_start, rhs_len); - - long col1 = strtol(lhs, NULL, 10); - long col2 = strtol(rhs, NULL, 10); - - int colcount1 = 0; - int colcount2 = 0; - while(tup1[colcount1]) { colcount1++; } - while(tup2[colcount2]) { colcount2++; } - - if(colcount1 <= col1 || colcount2 <= col2) { - printf("not enough columns for join!\n"); - match = 0; - } else if(!strcmp(op,"=")) { - if(strcmp(tup1[col1], tup2[col2])) { - match = 0; - } + switch(lhs_colreftype) { + case colstr_typ: { + // lhs_str = cmp->lhs.colent->u.colstr; + abort(); // xxx lookup column number in schema + } break; + case colint_typ: { + *colnum = colent->u.colnum; + } break; + default: abort(); return 0; //xxx + } + + if(*colnum >= tup.count) { return 0; } + *datatype = tup.type[*colnum]; + + switch(*datatype) { + case int64_typ: { + *val_int64 = tup.col[*colnum].int64; + } break; + case string_typ: { + *val_string = tup.col[*colnum].string; + } break; + default: abort(); return 0; //xxx + } + + } break; + case val_typ: { + *datatype = valent->typ; + switch(*datatype) { + case int64_typ: { + *val_int64 = valent->u.integ; //tup.col[*colnum].int64; + } break; + case string_typ: { + *val_string = valent->u.str; //tup.col[*colnum].string; + } break; + default: abort(); return 0; + } + } break; + default: abort(); return 0; + } + return 1; +} + +static int matchPredicate(tuple_t tup1, tuple_t tup2, cmp_entry* cmp) { + datatype_t lhs_datatype; + val_col_int lhs_colnum; + int64_t lhs_int64; + char* lhs_string; + + datatype_t rhs_datatype; + val_col_int rhs_colnum; + int64_t rhs_int64; + char* rhs_string; + + if(!resolveColName(&lhs_colnum, &lhs_datatype, &lhs_int64, &lhs_string, tup1, cmp->lhs_typ, cmp->lhs.colent, cmp->lhs.valent)) { printf("Tuple too short\n"); return 0; } + if(!resolveColName(&rhs_colnum, &rhs_datatype, &rhs_int64, &rhs_string, tup2, cmp->rhs_typ, cmp->rhs.colent, cmp->rhs.valent)) { printf("Tuple too short\n"); return 0; } + + switch(cmp->comparator) { + case equal_typ: { + if(lhs_datatype!=rhs_datatype) { return 0; } + switch(lhs_datatype) { + case int64_typ: { + if(lhs_int64==rhs_int64) { return 1; } + } break; + case string_typ: { + if(!strcmp(lhs_string, rhs_string)) { return 1; } + } break; + default: abort(); + } + } break; + default: abort(); + } + return 0; +} +static int matchComparator(tuple_t tup1, + tuple_t tup2, + cmp_tuple * pred) { + int match = 1; + for(int i = 0; i < pred->count; i++) { + if(!matchPredicate(tup1,tup2,pred->ents[i])) { + //printf("failed on pred %d\n",i); + match = 0; + break; } - col++; - free(rhs); - free(lhs); - free(op); } return match; } lladdIterator_t* ReferentialAlgebra_Join(int xid, - char ** pred, lladdIterator_t * outer_it, - lladdIterator_t * inner_it) { + lladdIterator_t * inner_it, + cmp_tuple * pred) { if(!(outer_it && inner_it)) { - if(pred) { tplFree(pred); } return 0; } @@ -579,34 +695,26 @@ lladdIterator_t* ReferentialAlgebra_Join(int xid, j->inner_it = inner_it; j->outer_it = outer_it; + j->have_outer = 0; j->pred = pred; - j->inner_tpls = calloc(1, sizeof(char ***)); - j->inner_strs = calloc(1, sizeof(char **)); - j->freethese = malloc(sizeof(char**)); + j->inner_tpls = calloc(1, sizeof(tuple_t*)); int i = 0; while(Titerator_next(xid, inner_it)) { - char * in_val; + byte * in_val; Titerator_value(xid, inner_it, (byte**)&in_val); - int count; - char ** tok = split((char*)in_val, (j->freethese)+i, &count, ", "); - j->inner_tpls = realloc(j->inner_tpls, sizeof(char***)*(i+2)); - j->inner_strs = realloc(j->inner_strs, sizeof(char**)*(i+2)); - j->freethese = realloc(j->freethese, sizeof(char**)*(i+2)); - j->inner_tpls[i] = tok; - j->inner_tpls[i+1] = 0; - j->freethese[i+1] = 0; - j->inner_strs[i] = strdup(in_val); - j->inner_strs[i+1] = 0; + j->inner_tpls = realloc(j->inner_tpls, sizeof(tuple_t)*(i+1)); + j->inner_tpls[i] = tupleDup(*(tuple_t*)in_val); Titerator_tupleDone(xid, inner_it); i++; } + j->inner_count = i; j->inner_pos = 0; - j->outer_tpl = 0; + j->have_outer = 0; lladdIterator_t * new_it = malloc(sizeof(lladdIterator_t)); new_it->type = JOIN_ITERATOR; new_it->impl = j; - return ReferentialAlgebra_KeyValCat(xid,new_it); + return new_it; } @@ -614,39 +722,52 @@ static void j_close(int xid, void * it) { join_impl * j = it; Titerator_close(xid,j->outer_it); Titerator_close(xid,j->inner_it); - for(int i = 0; j->inner_tpls[i]; i++) { + for(int i = 0; i < j->inner_count; i++) { // tplFree(j->inner_tpls[i]); - free(j->freethese[i]); - free(j->inner_strs[i]); - free(j->inner_tpls[i]); + //free(j->freethese[i]); + // free(j->inner_strs[i]); + tupleFree(j->inner_tpls[i]); } - tplFree(j->pred); + // tplFree(j->pred); free(j->inner_tpls); - free(j->inner_strs); - free(j->freethese); - if(j->freeouter) { free(j->freeouter); } + + if(j->have_outer) { + tupleFree(j->outer_tpl); + } // don't free pred; that's the caller's problem. free(j); } static int j_next(int xid, void * it) { join_impl * j = it; while(1) { - if((!j->inner_tpls[j->inner_pos]) || (!j->outer_tpl)) { + //printf("checking %d\n", j->inner_pos); + if((j->inner_pos == j->inner_count) || (!j->have_outer)) { j->inner_pos = 0; - Titerator_tupleDone(xid, j->outer_it); + if(j->have_outer) { + Titerator_tupleDone(xid, j->outer_it); + tupleFree(j->t); + } if(Titerator_next(xid, j->outer_it)) { - int count; - Titerator_value(xid, j->outer_it, (byte**)&j->outer_str); - j->outer_tpl = split((char*)j->outer_str, &j->freeouter, &count, ", "); + byte * this_tpl; + Titerator_value(xid, j->outer_it, &this_tpl); + j->outer_tpl = *(tuple_t*)this_tpl; } else { + j->have_outer = 0; return 0; } } - if(matchComparator(j->outer_tpl, j->inner_tpls[j->inner_pos], j->pred)) { - j->inner_pos++; - return 1; - } else { - j->inner_pos++; + while(j->inner_pos != j->inner_count) { + if(matchComparator(j->outer_tpl, j->inner_tpls[j->inner_pos], j->pred)) { + j->have_outer = 1; + j->t = tupleAlloc(); + j->t = tupleCatTuple(j->t, j->outer_tpl); + j->t = tupleCatTuple(j->t, j->inner_tpls[j->inner_pos]); + j->inner_pos++; + return 1; + } else { + j->have_outer = 0; + j->inner_pos++; + } } } } @@ -655,30 +776,66 @@ static int j_tryNext(int xid, void * it) { } static int j_key(int xid, void * it, byte ** key) { join_impl * j = it; - *key = (byte*)j->outer_str; + *key = (byte*)&(j->t); return 1; } static int j_value(int xid, void * it, byte ** val) { join_impl * j = it; - *val = (byte*)j->inner_strs[j->inner_pos-1]; + *val = (byte*)&(j->t); //inner_tpls[j->inner_pos-1]); return 1; } static void j_tupleDone(int xid, void * it) { - join_impl * j = it; - free(j->outer_tpl); - free(j->freeouter); - j->outer_tpl = 0; - j->freeouter = 0; } static void j_releaseLock(int xid, void *it) { // noop } + +////////////////////////////////////////////////////////////////////////////////// +/// /// +/// AST INTERPRETER FUNCTIONS /// +/// /// +////////////////////////////////////////////////////////////////////////////////// + +lladdIterator_t* ReferentialAlgebra_ExecuteQuery(int xid, + ReferentialAlgebra_context_t* c, + union_qry *q) { + + if(q->count != 1) { abort(); } // unimplemented; + + switch(q->ents[0]->typ) { + case scan_typ: { + return ReferentialAlgebra_OpenTableScanner(xid, c->hash, q->ents[0]->u.scn->table); + } break; + case select_typ: { + return ReferentialAlgebra_Select(xid, + ReferentialAlgebra_ExecuteQuery(xid, c, q->ents[0]->u.sel->q), + q->ents[0]->u.sel->t); + } break; + case project_typ: { + return ReferentialAlgebra_Project(xid, + ReferentialAlgebra_ExecuteQuery(xid, c, q->ents[0]->u.prj->q), + q->ents[0]->u.prj->t); + } break; + case join_typ: { + return ReferentialAlgebra_Join(xid, + ReferentialAlgebra_ExecuteQuery(xid, c, q->ents[0]->u.jn->lhs), + ReferentialAlgebra_ExecuteQuery(xid, c, q->ents[0]->u.jn->rhs), + q->ents[0]->u.jn->t); + } break; + default: abort(); // select, project, join, etc unimplemented. + } + +} + ////////////////////////////////////////////////////////////////////////////////// /// /// /// ININTIALIZATION /// /// /// ////////////////////////////////////////////////////////////////////////////////// +/** + Initialize module (Must be called before anything else in this file). + */ void ReferentialAlgebra_init() { lladdIterator_def_t select_def = { s_close, s_next, s_tryNext, s_key, s_value, s_tupleDone, s_releaseLock @@ -692,218 +849,35 @@ void ReferentialAlgebra_init() { kv_close, kv_next, kv_tryNext, kv_key, kv_value, kv_tupleDone, kv_releaseLock }; lladdIterator_register(KEYVAL_ITERATOR, keyval_def); + lladdIterator_def_t keyvaltup_def = { + kvt_close, kvt_next, kvt_tryNext, kvt_key, kvt_value, kvt_tupleDone, kvt_releaseLock + }; + lladdIterator_register(KEYVALTUP_ITERATOR, keyvaltup_def); lladdIterator_def_t j_def = { j_close, j_next, j_tryNext, j_key, j_value, j_tupleDone, j_releaseLock }; lladdIterator_register(JOIN_ITERATOR, j_def); } - - -////////////////////////////////////////////////////////////////////////////////// -/// /// -/// PARSER /// -/// /// -////////////////////////////////////////////////////////////////////////////////// - -// Reserved characters: (, ), [, ], ",", " ". -// Grammar: -// E = (s [tuple] E) | (p [tuple] E) | (j [tuple] E E) | TABLENAME -// tuple = V | V,tuple -// V = string of non-reserved characters -// TABLENAME = string of non-reserved characters - -#define LPAREN '{' -#define RPAREN '}' -#define LBRACKET '(' -#define RBRACKET ')' -#define COMMA ',' -#define SPACE ' ' -#define STRING 's' -#define EOS '\0' -/* - @return one of the above. If returns STRING, set *tok to be the new - token. (*tok should be freed by caller in this case) +/** */ -int nextToken(char ** head, char ** tok, int breakOnSpace); +ReferentialAlgebra_context_t * ReferentialAlgebra_openContext(int xid, recordid rid) { + ReferentialAlgebra_context_t * ret = malloc(sizeof(ReferentialAlgebra_context_t)); + ret->hash = rid; -char** parseTuple(char ** head) { - char **tok = calloc(1,sizeof(char*));; - char * mytok; - char ret = nextToken(head, &mytok,0); - assert(ret == LBRACKET); - int count = 0; - while(1) { - ret = nextToken(head, &mytok,0); - if(ret == RBRACKET) { - break; - } - if(ret == COMMA) { - tok = realloc(tok, sizeof(char*)*(count+1)); - tok[count] = 0; - tok[count-1] = calloc(1,sizeof(char)); - } else if(ret == STRING) { - count++; - tok = realloc(tok, sizeof(char*)*(count+1)); - tok[count] = 0; - tok[count-1] = mytok; - ret = nextToken(head, &mytok,0); - if(ret == STRING) { free(mytok); } - if(ret == RBRACKET) { - break; - } - if(ret != COMMA) { - tplFree(tok); - return 0; - } - } else { - tplFree(tok); - return 0; - } - } - return tok; + return ret; } -lladdIterator_t * parseExpression(int xid, recordid catalog, - char **head) { - while(isblank(**head)) { (*head)++; } - if(**head == LPAREN) { - (*head)++; - lladdIterator_t * it; - if(**head == 's') { - (*head)++; - char ** pred = parseTuple(head); - lladdIterator_t * it2 = parseExpression(xid, catalog, head); - it = ReferentialAlgebra_Select(xid, it2, pred); - if(it2 && !it) { - Titerator_close(xid,it2); - } - } else if(**head == 'p') { - (*head)++; - char ** pred = parseTuple(head); - lladdIterator_t * it2 = parseExpression(xid, catalog, head); - it = ReferentialAlgebra_Project(xid, it2, pred); - if(it2 && !it) { - Titerator_close(xid,it2); - } - } else if(**head == 'j') { - (*head)++; - char ** pred = parseTuple(head); - lladdIterator_t * outer = parseExpression(xid, catalog, head); - lladdIterator_t * inner = parseExpression(xid, catalog, head); - it = ReferentialAlgebra_Join(xid, pred, outer, inner); - if(outer && !it) { - Titerator_close(xid,outer); - } - if(inner && !it) { - Titerator_close(xid,inner); - } - } else { - printf("Unknown operator\n"); - it = 0; - } - if(!it) { - printf("parse error\n"); - return 0; - } - char * foo; - char ret = nextToken(head, &foo,0); - - if(ret != RPAREN) { - Titerator_close(xid,it); - return 0; - } else { - return it; - } - } else { - char * tablename; - char ret = nextToken(head, &tablename,1); - assert(ret == STRING); - lladdIterator_t * it2 = - ReferentialAlgebra_OpenTableScanner(xid, catalog, tablename); - free(tablename); - - if(!it2) { return 0; } - - - lladdIterator_t * it = ReferentialAlgebra_KeyValCat(xid,it2); - - return it; - } - abort(); -} - -int nextToken(char ** head, char ** tok, int breakOnSpace) { - while(isblank(**head) && **head) { (*head)++; } - switch(**head) { - case LPAREN: { - (*head)++; - return LPAREN; - } break; - case RPAREN: { - (*head)++; - return RPAREN; - } break; - case LBRACKET: { - (*head)++; - return LBRACKET; - } break; - case RBRACKET: { - (*head)++; - return RBRACKET; - } break; - case COMMA: { - (*head)++; - return COMMA; - } break; - case SPACE: { - (*head)++; - return SPACE; - } break; - default: { - if(!**head) { return EOS; }; - char * first = *head; - while(isalnum(**head) - ||isWhitelistChar(**head) - ||(**head==' '&&!breakOnSpace)) { - (*head)++; - } - char * last = *head; - *tok = calloc(1 + last - first, sizeof(char)); - // The remaining byte is the null terminator - strncpy(*tok, first, last - first); - int i = (last-first)-1; - int firstloop = 1; - while((*tok)[i] == ' ') { - (*tok)[i] = '\0'; - i++; - if(firstloop) { - (*head)--; - firstloop = 0; - } - } - return STRING; - } break; - } -} - -char ** executeQuery(int xid, recordid hash, char * line) { - char * lineptr = line; - - lladdIterator_t * it = parseExpression(xid,hash,&lineptr); - if(it) { - char ** tuples = malloc(sizeof(char*)); - int count = 0; - while(Titerator_next(xid, it)) { - count++; - tuples = realloc(tuples, sizeof(char*)*(count+1)); - Titerator_value(xid,it,(byte**)(tuples+count-1)); - tuples[count-1] = strdup(tuples[count-1]); - Titerator_tupleDone(xid,it); - } - Titerator_close(xid,it); - tuples[count] = 0; - return tuples; - } else { - return 0; - } +recordid ReferentialAlgebra_allocContext(int xid) { + recordid hash = ThashCreate(xid, VARIABLE_LENGTH, VARIABLE_LENGTH); + tuple_t tpl = tupleRid(hash); + tpl = tupleCatInt64(tpl,string_typ); + tpl = tupleCatInt64(tpl,int64_typ); + tpl = tupleCatInt64(tpl,int64_typ); + tpl = tupleCatInt64(tpl,int64_typ); + tpl = tupleCatInt64(tpl,star_typ); + size_t tplLen = 0; + byte * tplBytes = byteTuple(tpl,&tplLen); + ThashInsert(xid,hash,(byte*)"TABLES",strlen("TABLES")+1,tplBytes,tplLen); + free(tplBytes); + return hash; } diff --git a/src/apps/referential/algebra.h b/src/apps/referential/algebra.h index e2ff865..b7bad2b 100644 --- a/src/apps/referential/algebra.h +++ b/src/apps/referential/algebra.h @@ -1,19 +1,29 @@ #ifndef __ALGEBRA_H #define __ALGEBRA_H + +#include "lang/ast.h" + +typedef struct { + recordid hash; +} ReferentialAlgebra_context_t; + +lladdIterator_t* ReferentialAlgebra_ExecuteQuery(int xid, + ReferentialAlgebra_context_t* c, union_qry *q); + lladdIterator_t* ReferentialAlgebra_OpenTableScanner(int xid, recordid catalog, char * tablename); lladdIterator_t* ReferentialAlgebra_Select(int xid, lladdIterator_t* it, - char ** predicate); + union_cmp * predicate); lladdIterator_t* ReferentialAlgebra_Project(int xid, lladdIterator_t * it, - char ** project); + col_tuple * project); +lladdIterator_t* ReferentialAlgebra_Join(int xid, + lladdIterator_t * outer_it, + lladdIterator_t * inner_it, + cmp_tuple * cmp); lladdIterator_t* ReferentialAlgebra_KeyValCat(int xid, lladdIterator_t * it); -char * tplRid(recordid rid); -recordid ridTpl(char * tpl); void ReferentialAlgebra_init(); - -char ** executeQuery(int xid, recordid hash, char * line); -lladdIterator_t * parseExpression(int xid, recordid catalog, char **head); -char** parseTuple(char ** head); +ReferentialAlgebra_context_t * ReferentialAlgebra_openContext(int xid, recordid rid); +recordid ReferentialAlgebra_allocContext(int xid); #endif diff --git a/src/apps/referential/ddl.c b/src/apps/referential/ddl.c new file mode 100644 index 0000000..c9dcb6f --- /dev/null +++ b/src/apps/referential/ddl.c @@ -0,0 +1,20 @@ +#include "ddl.h" +#include +#include +int ReferentialDDL_CreateTable(int xid, ReferentialAlgebra_context_t*context, create *q) { + recordid newTable = ThashCreate(xid, VARIABLE_LENGTH, VARIABLE_LENGTH); // XXX assumes first col is a string! + tuple_t ridtpl = tupleRid(newTable); + tuple_t union_typ_tup = tupleUnion_typ(q->schema); + assert(union_typ_tup.count); + assert(union_typ_tup.col[0].int64 == string_typ); // XXX + + ridtpl = tupleCatTuple(ridtpl,union_typ_tup); + tupleFree(union_typ_tup); + + size_t tplLen; + byte * tplBytes = byteTuple(ridtpl,&tplLen); + + ThashInsert(xid,context->hash,(byte*)q->tbl,strlen(q->tbl)+1,tplBytes,tplLen); + free(tplBytes); + return 1; +} diff --git a/src/apps/referential/ddl.h b/src/apps/referential/ddl.h new file mode 100644 index 0000000..2d786a9 --- /dev/null +++ b/src/apps/referential/ddl.h @@ -0,0 +1,6 @@ +#ifndef DDL_H +#define DDL_H +#include "algebra.h" +#include "lang/ast.h" +int ReferentialDDL_CreateTable(int xid, ReferentialAlgebra_context_t*context, create *q); +#endif //DDL_H diff --git a/src/apps/referential/dml.c b/src/apps/referential/dml.c index b49b072..423d8b8 100644 --- a/src/apps/referential/dml.c +++ b/src/apps/referential/dml.c @@ -1,9 +1,13 @@ +#define _GNU_SOURCE + #include #include #include +#include #include "dml.h" #include "algebra.h" +/* int executeInsert(int xid, recordid tables, char * insert) { char * linecopy = strdup(insert+strlen("insert")); char * strtoks; @@ -61,3 +65,89 @@ int executeDelete(int xid, recordid tables, char * delete) { free(linecopy); return 1; } +*/ +static recordid ReferentialDML_lookupTableRid(int xid, ReferentialAlgebra_context_t*context, char * tablename) { + expr_list * results = 0; + char * line; + asprintf(&line, "query {p ($1,$2,$3) {s ($0=\"%s\") TABLES} }", tablename); + + //XXX memory leak! + parse(line,&results); + + assert(results); //XXX + assert(results->count == 1); //XXX + + lladdIterator_t * it = ReferentialAlgebra_ExecuteQuery(xid, context, results->ents[0]->u.q); + recordid tableRid; + + if(it) { + int first = 1; + while(Titerator_next(xid,it)) { + assert(first); + first = 0; + byte * tup; + Titerator_value(xid, it, &tup); + tableRid = ridTuple(*(tuple_t*)tup); + } + Titerator_close(xid, it); + } else { + abort(); //XXX + } + return tableRid; +} + +int ReferentialDML_InsertTuple(int xid, ReferentialAlgebra_context_t*context, char * tablename, tuple_t t) { + //XXX assumes table format is key value, starting with a string. + tuple_t val = tupleTail(t, 1); + size_t val_len; + byte * val_byte = byteTuple(val,&val_len); + + recordid tableRid = ReferentialDML_lookupTableRid(xid,context,tablename); + + if(t.type[0] == string_typ) { + ThashInsert(xid, tableRid, (byte*)t.col[0].string, 1+strlen(t.col[0].string), val_byte, val_len); + } else if(t.type[0] == int64_typ) { + abort(); // int keys not supported yet + ThashInsert(xid, tableRid, (byte*)&t.col[0].int64, sizeof(int64_t), val_byte, val_len); + } else { + abort(); + } + + free(val_byte); + tupleFree(val); + return 0; +} +int ReferentialDML_DeleteTuple(int xid, ReferentialAlgebra_context_t*context, char * tablename, tuple_t t) { + //XXX assumes table format is key value, starting with a string. + // tuple_t val = tupleTail(t, 1); + // size_t val_len; + // byte * val_byte = byteTuple(val,&val_len); + + recordid tableRid = ReferentialDML_lookupTableRid(xid,context,tablename); + + if(t.type[0] == string_typ) { + ThashRemove(xid, tableRid, (byte*)t.col[0].string, 1+strlen(t.col[0].string)); //, val_byte, val_len); + } else if(t.type[0] == int64_typ) { + abort(); // int keys not supported yet + ThashRemove(xid, tableRid, (byte*)&t.col[0].int64, sizeof(int64_t)); //, val_byte, val_len); + } else { + abort(); + } + + //free(val_byte); + //tupleFree(val); + return 0; +} + +int ReferentialDML_ExecuteInsert(int xid, ReferentialAlgebra_context_t*context, insert *i) { + tuple_t t = tupleVal_tuple(i->t); + int ret = ReferentialDML_InsertTuple(xid, context, i->tbl, t); + tupleFree(t); + return ret; +} +int ReferentialDML_ExecuteDelete(int xid, ReferentialAlgebra_context_t*context, delete *d) { + tuple_t t = tupleVal_tuple(d->t); + int ret = ReferentialDML_DeleteTuple(xid, context, d->tbl, t); + tupleFree(t); + return ret; +} diff --git a/src/apps/referential/dml.h b/src/apps/referential/dml.h index 447f096..cceb489 100644 --- a/src/apps/referential/dml.h +++ b/src/apps/referential/dml.h @@ -1,4 +1,6 @@ #include +#include "algebra.h" +#include "lang/ast.h" -int executeDelete(int xid, recordid tables, char * delete); -int executeInsert(int xid, recordid tables, char *insert); +int ReferentialDML_ExecuteInsert(int xid, ReferentialAlgebra_context_t*context, insert *i); +int ReferentialDML_ExecuteDelete(int xid, ReferentialAlgebra_context_t*context, delete *i); diff --git a/src/apps/referential/lang/CMakeLists.txt b/src/apps/referential/lang/CMakeLists.txt new file mode 100644 index 0000000..a8bfe3a --- /dev/null +++ b/src/apps/referential/lang/CMakeLists.txt @@ -0,0 +1,10 @@ +BISON_TARGET(RefParser ${CMAKE_CURRENT_SOURCE_DIR}/parse.y ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c) +FLEX_TARGET(RefParser ${CMAKE_CURRENT_SOURCE_DIR}/lexer.lex ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.c) +#SET(INCLUDE_DIR ${INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) +#COPY_FILE(${CMAKE_CURRENT_SOURCE_DIR}/ast.h ${CMAKE_CURRENT_BINARY_DIR}/ast.h) +ADD_LIBRARY(refparse ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.c ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c ${CMAKE_CURRENT_SOURCE_DIR}/ast.c) +ADD_EXECUTABLE(parser ${CMAKE_CURRENT_BINARY_DIR}/lex.yy.c ${CMAKE_CURRENT_BINARY_DIR}/y.tab.c ${CMAKE_CURRENT_SOURCE_DIR}/ast.c ${CMAKE_CURRENT_SOURCE_DIR}/parse.c) +SET_TARGET_PROPERTIES(refparse PROPERTIES COMPILE_FLAGS "-Wno-implicit -Wno-unused -I ${CMAKE_CURRENT_SOURCE_DIR}") +SET_TARGET_PROPERTIES(parser PROPERTIES COMPILE_FLAGS "-Wno-implicit -Wno-unused -I ${CMAKE_CURRENT_SOURCE_DIR}") +ADD_TEST(test_parser ${CMAKE_CURRENT_SOURCE_DIR}/test_parser.pl) + diff --git a/src/apps/referential/lang/ast.c b/src/apps/referential/lang/ast.c new file mode 100644 index 0000000..6decc44 --- /dev/null +++ b/src/apps/referential/lang/ast.c @@ -0,0 +1,368 @@ +#define _GNU_SOURCE +#include + +#include +#include +#include "ast.h" + +/* +int walk(const expr_list * el) { + return walk_expr_list(el); +} + +#define WALK_LIST(type, child_type) \ +int walk_##type(const type * x) { \ + int ret = 0; \ + for(int i = 0; i < x->count; i++) { \ + ret |= walk_##child_type(x->ents[i]); \ + } \ + return ret; \ +} + +#define WALK_LIST_DECL(type) \ + int walk_##type(const type * x); + +#define WALK_LEAF(type) \ +int walk_##type(const type * x) { \ + return 0; \ +} + +#define WALK_LEAF_DECL(type) \ +int walk_##type(const type * x); + +WALK_LIST_DECL(expr_list) +WALK_LEAF_DECL(expr) + +WALK_LIST(expr_list, expr) +WALK_LEAF(expr) +*/ +char * astrncat(char * dest, const char * src) { + size_t destlen = dest ? strlen(dest) : 0; + size_t srclen = strlen(src); + dest = realloc(dest, destlen+srclen+1); + if(srclen && !destlen) { dest[0] = 0; } + /* printf("src =>%s<=",src); */ + strcat(dest, src); + return dest; +} +char * afstrncat(char *dest, char * src) { + dest = astrncat(dest, src); + free(src); + return dest; +} + + +char * pp_expr_list(const expr_list* el) { + char * ret = 0; + int i; + for(i = 0; i < el->count; i++) { + ret = afstrncat(ret, pp_expr(el->ents[i])); + ret = astrncat(ret, "\n"); + } + return ret; +} +char * pp_expr(const expr* e) { + char * ret = 0; + switch(e->typ) { + case query_typ: { + ret = astrncat(ret, "query "); + ret = afstrncat(ret, pp_union_qry(e->u.q)); + } break; + case insert_typ: { + ret = astrncat(ret, "insert "); + ret = afstrncat(ret, pp_insert(e->u.i)); + } break; + case delete_typ: { + ret = astrncat(ret, "delete "); + ret = afstrncat(ret, pp_delete(e->u.d)); + } break; + case create_typ: { + ret = astrncat(ret, "create "); + ret = afstrncat(ret, pp_create(e->u.c)); + } break; + default: abort(); + } + return ret; +} +char * pp_query(const query* q) { + char * ret = 0; + switch(q->typ) { + case scan_typ: { + ret = afstrncat(ret, pp_q_scan(q->u.scn)); + } break; + case table_star_typ: { + ret = astrncat(ret, "*"); + } break; + case select_typ: { + ret = astrncat(ret, "{s "); + ret = afstrncat(ret, pp_union_cmp(q->u.sel->t)); + ret = astrncat(ret, " "); + ret = afstrncat(ret, pp_union_qry(q->u.sel->q)); + ret = astrncat(ret, "}"); + } break; + case project_typ: { + ret = astrncat(ret, "{p "); + ret = afstrncat(ret, pp_col_tuple(q->u.prj->t)); + ret = astrncat(ret, " "); + ret = afstrncat(ret, pp_union_qry(q->u.prj->q)); + ret = astrncat(ret, "}"); + } break; + case join_typ: { + ret = astrncat(ret, "{j "); + ret = afstrncat(ret, pp_cmp_tuple(q->u.jn->t)); + ret = astrncat(ret, " "); + ret = afstrncat(ret, pp_union_qry(q->u.jn->lhs)); + ret = astrncat(ret, " "); + ret = afstrncat(ret, pp_union_qry(q->u.jn->rhs)); + ret = astrncat(ret, "}"); + } break; + default: abort(); + } + return ret; +} +char * pp_create(const create * c){ + char * ret = 0; + ret = astrncat(ret, c->tbl); + ret = astrncat(ret, " "); + ret = astrncat(ret, pp_union_typ(c->schema)); + return ret; +} +char * pp_q_scan(const q_scan* s) { + char * ret = 0; + asprintf(&ret, "%s", s->table); + return ret; +} +char * pp_insert(const insert * i) { + char * ret = 0; + asprintf(&ret, "%s ", i->tbl); + ret = afstrncat(ret, pp_val_tuple(i->t)); + return ret; +} +char * pp_delete(const delete * d) { + char * ret = 0; + asprintf(&ret, "%s ", d->tbl); + ret = afstrncat(ret, pp_val_tuple(d->t)); + return ret; +} +/*char * pp_pat_tuple(const pat_tuple * p) { + int i; + char * ret = 0; + int first = 1; + ret = astrncat(ret,"("); + for(i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,", "); + } else { + first = 0; + } + ret = afstrncat(ret, pp_pat_entry(p->ents[i])); + } + ret = astrncat(ret,")"); + return ret; + } */ + +char * pp_val_tuple(const val_tuple * p) { + int i; + char * ret = 0; + int first = 1; + ret = astrncat(ret,"("); + for(i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,", "); + } else { + first = 0; + } + ret = afstrncat(ret, pp_val_entry(p->ents[i])); + } + ret = astrncat(ret,")"); + return ret; +} +char * pp_col_tuple(const col_tuple * p) { + int i; + char * ret = 0; + int first = 1; + ret = astrncat(ret,"("); + for(i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,", "); + } else { + first = 0; + } + ret = afstrncat(ret, pp_col_entry(p->ents[i])); + } + ret = astrncat(ret,")"); + return ret; +} +char * pp_cmp_tuple(const cmp_tuple * p) { + int i; + char * ret = 0; + int first = 1; + ret = astrncat(ret,"("); + for(i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,", "); + } else { + first = 0; + } + ret = afstrncat(ret, pp_cmp_entry(p->ents[i])); + } + ret = astrncat(ret,")"); + return ret; +} +char * pp_typ_tuple(const typ_tuple * p) { + int i; + char * ret = 0; + int first = 1; + ret = astrncat(ret,"("); + for(i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,", "); + } else { + first = 0; + } + ret = afstrncat(ret, pp_typ_entry(p->ents[i])); + } + ret = astrncat(ret,")"); + return ret; +} +char * pp_union_qry(const union_qry * p) { + char * ret = 0; + int first = 1; + for(int i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,"|"); + } else { + first = 0; + } + ret = astrncat(ret, pp_query(p->ents[i])); + } + return ret; +} +char * pp_union_typ(const union_typ * p) { + char * ret = 0; + int first = 1; + for(int i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,"|"); + } else { + first = 0; + } + ret = astrncat(ret, pp_typ_tuple(p->ents[i])); + } + return ret; +} +char * pp_union_cmp(const union_cmp * p) { + char * ret = 0; + int first = 1; + for(int i = 0; i < p->count; i++) { + if(!first) { + ret = astrncat(ret,"|"); + } else { + first = 0; + } + ret = astrncat(ret, pp_cmp_tuple(p->ents[i])); + } + return ret; +} +/*char * pp_pat_entry(const pat_entry * p) { + char * ret = 0; + switch(p->typ) { + case star_typ: { + asprintf(&ret,"*"); + } break; + case ident_typ: { + asprintf(&ret,"%s",p->u.ident); + } break; + case int_typ: { + asprintf(&ret,"%d",p->u.integ); + } break; + case string_typ: { + asprintf(&ret,"\"%s\"",p->u.str); + } break; + default: abort(); + } + return ret; + } */ +char * pp_val_entry(const val_entry * p) { + char * ret = 0; + switch(p->typ) { + case ident_typ: { + asprintf(&ret,"%s",p->u.ident); + } break; + case int64_typ: { + asprintf(&ret,"%lld",(long long int)p->u.integ); + } break; + case string_typ: { + asprintf(&ret,"\"%s\"",p->u.str); + } break; + default: abort(); + } + return ret; +} +char * pp_col_entry(const col_entry * p) { + char * ret = 0; + switch(p->typ) { + case colint_typ: { + asprintf(&ret,"$%d",p->u.colnum); + } break; + case colstr_typ: { + asprintf(&ret,"$%s",p->u.colstr); + } break; + case string_typ: { + asprintf(&ret,"%s",p->u.colstr); + } break; + default: abort(); + } + return ret; +} +char * pp_cmp_entry(const cmp_entry * p) { + char * ret = 0; + switch(p->lhs_typ) { + case col_typ: { + ret = afstrncat(ret, pp_col_entry(p->lhs.colent)); + } break; + case val_typ: { + ret = afstrncat(ret, pp_val_entry(p->lhs.valent)); + } break; + default: abort(); + } + + switch(p->comparator) { + case equal_typ: { + ret = astrncat(ret, "="); + } break; + default: abort(); + } + + switch(p->rhs_typ) { + case col_typ: { + ret = afstrncat(ret, pp_col_entry(p->rhs.colent)); + } break; + case string_typ: { + ret = afstrncat(ret, pp_col_entry(p->rhs.colent)); + } break; + case val_typ: { + ret = afstrncat(ret, pp_val_entry(p->rhs.valent)); + } break; + default: abort(); + } + return ret; +} +char * pp_typ_entry(const typ_entry * p) { + char * ret = 0; + switch(p->typ) { + case typ_typ: { + switch(p->u.type) { + case int64_typ: { + ret = astrncat(ret, "int"); + } break; + case string_typ: { + ret = astrncat(ret, "string"); + } break; + default: abort(); + } + } break; + default: abort(); + } + return ret; +} diff --git a/src/apps/referential/lang/ast.h b/src/apps/referential/lang/ast.h new file mode 100644 index 0000000..2146463 --- /dev/null +++ b/src/apps/referential/lang/ast.h @@ -0,0 +1,246 @@ +#ifndef _REFER_AST_H +#define _REFER_AST_H +#include + +typedef struct expr_list expr_list; +typedef struct expr expr; +typedef struct query query; +typedef struct insert insert; +typedef struct delete delete; +typedef struct create create; + +typedef struct q_scan q_scan; +typedef struct q_select q_select; +typedef struct q_project q_project; +typedef struct q_join q_join; + +//typedef struct pat_tuple pat_tuple; +typedef struct cmp_tuple cmp_tuple; +typedef struct col_tuple col_tuple; +typedef struct val_tuple val_tuple; +typedef struct typ_tuple typ_tuple; + +typedef struct union_typ union_typ; +typedef struct union_cmp union_cmp; +typedef struct union_qry union_qry; + +//typedef struct pat_entry pat_entry; +typedef struct cmp_entry cmp_entry; +typedef struct col_entry col_entry; +typedef struct val_entry val_entry; +typedef struct typ_entry typ_entry; + +typedef char* table; +typedef char* ident; + +typedef int val_ent_wildcard; +typedef char* val_ent_ident; +typedef int64_t val_ent_int; +typedef char* val_ent_string; + +#include "../tuple.h" // for datatypes. +/*typedef enum { + integer_data_typ, + string_data_typ + } val_ent_typ;*/ +typedef int val_col_int; +typedef char* val_col_string; + +struct expr_list { + int count; + expr ** ents; +}; +char * pp_expr_list(const expr_list*); +struct expr { + enum expr_typ { + query_typ, + insert_typ, + delete_typ, + create_typ + } typ; + union { + union_qry * q; + insert * i; + delete * d; + create * c; + } u; +}; +char * pp_expr(const expr*); + +struct query { + enum query_typ { + scan_typ, + table_star_typ, + select_typ, + project_typ, + join_typ + } typ; + union { + q_scan * scn; + q_select * sel; + q_project* prj; + q_join * jn; + } u; +}; +char * pp_query(const query*); +struct create { + char * tbl; + union_typ * schema; +}; +char * pp_create(const create*); + +struct q_scan { + char * table; +}; +char * pp_q_scan(const q_scan*); + +struct q_select { + union_cmp * t; + union_qry * q; +}; +//char * pp_q_select(const q_select*); + +struct q_project { + col_tuple * t; + union_qry * q; +}; +//char * pp_q_project(const q_project*); + +struct q_join { + cmp_tuple * t; + union_qry * lhs; + union_qry * rhs; +}; +//char * pp_q_join(const q_join*); + +struct insert { + table tbl; + val_tuple * t; +}; +char * pp_insert(const insert*); + +struct delete { + table tbl; + val_tuple * t; +}; +char * pp_delete(const delete*); + +enum cmp_typ { + equal_typ +}; + +/*struct pat_tuple { + int count; + pat_entry ** ents; // XXX tuple type? +}; +char * pp_pat_tuple(const pat_tuple*); */ + +struct val_tuple { + int count; + val_entry ** ents; +}; +char * pp_val_tuple(const val_tuple*); + +struct col_tuple { + int count; + col_entry ** ents; +}; +char * pp_col_tuple(const col_tuple*); +struct cmp_tuple { + int count; + cmp_entry ** ents; +}; +char * pp_cmp_tuple(const cmp_tuple*); +struct typ_tuple { + int count; + typ_entry ** ents; +}; +char * pp_typ_tuple(const typ_tuple*); +/*struct pat_entry { + enum tup_entry_typ typ; + union { + val_ent_wildcard wc; + val_ent_ident ident; + val_ent_int integ; + val_ent_string str; + } u; +}; +char * pp_pat_entry(const pat_entry*); */ +struct val_entry { + datatype_t typ; + union { + val_ent_ident ident; + val_ent_int integ; + val_ent_string str; + } u; +}; +char * pp_val_entry(const val_entry*); +struct col_entry { + datatype_t typ; + union { + val_col_string colstr; + val_col_int colnum; + } u; +}; +char * pp_col_entry(const col_entry*); +struct typ_entry { + datatype_t typ; + union { + datatype_t type; + } u; +}; +char * pp_typ_entry(const typ_entry*); + +struct union_typ { + int count; + typ_tuple ** ents; +}; +char * pp_union_typ(const union_typ*); +struct union_cmp { + int count; + cmp_tuple ** ents; +}; +char * pp_union_cmp(const union_cmp*); +struct union_qry { + int count; + query ** ents; +}; +char * pp_union_qry(const union_qry*); + +enum cmp_side_typ { + col_typ, + val_typ +}; +struct cmp_entry { + enum cmp_side_typ lhs_typ; + enum cmp_side_typ rhs_typ; + enum cmp_typ comparator; + union { + col_entry * colent; + val_entry * valent; + } lhs; + union { + col_entry * colent; + val_entry * valent; + } rhs; +}; +char * pp_cmp_entry(const cmp_entry*); + + +//int yyparse(); +extern expr_list * results; +void parse(char *buf, expr_list **result); + +char * astrncat(char *,const char *); +char * afstrncat(char *,char *); + +/*struct table { + char * name; +}; +char * pp_table(table*); */ + +/*struct ident { + char * name; +}; +char * pp_ident(ident*); */ +#endif// _REFER_AST_H diff --git a/src/apps/referential/lang/lexer.lex b/src/apps/referential/lang/lexer.lex new file mode 100644 index 0000000..99754f5 --- /dev/null +++ b/src/apps/referential/lang/lexer.lex @@ -0,0 +1,79 @@ +%{ +#include +#include +#include "ast.h" +#include "y.tab.h" +#include "parser_private.h" +//#define DBG(x) printf("%s\t",x); ECHO +#define DBG(x) + +#define PARM yyget_extra(yyscanner) + +#define YY_INPUT(buffer, res, max_size) \ + do { \ + if (PARM->pos >= PARM->length) \ + res = YY_NULL; \ + else \ + { \ + res = PARM->length - PARM->pos; \ + res > (int)max_size ? res = max_size : 0; \ + memcpy(buffer, PARM->buf + PARM->pos, res); \ + PARM->pos += res; \ + } \ + } while (0) + +//%option reentrant bison-bridge +//%option noyywrap +//%option nounput + +%} + +%option reentrant bison-bridge +%option noyywrap +%option nounput + +%START INTUPLE + +%% +"(" {DBG("LPAREN"); BEGIN INTUPLE; return LPAREN;} +")" {DBG("RPAREN"); BEGIN 0; return RPAREN;} +"{" {DBG("LBRACKET"); return LBRACKET;} +"}" {DBG("RBRACKET"); return RBRACKET;} +"," {DBG("COMMA"); return COMMA;} +"|" {DBG("BAR"); return BAR;} +"*" {DBG("STAR"); return STAR;} +"=" {DBG("EQUAL"); return EQUAL;} +"insert" {DBG("INSERT"); return INSERT;} +"i" {DBG("INSERT"); return INSERT;} +"delete" {DBG("DELETE"); return DELETE;} +"d" {DBG("DELETE"); return DELETE;} +"query" {DBG("QUERY"); return QUERY;} +"q" {DBG("QUERY"); return QUERY;} +"create" {DBG("CREATE"); return CREATE;} +"c" {DBG("CREATE"); return CREATE;} +"string" {DBG("STRING_TYPE"); return STRING_TYPE;} +"int" {DBG("INT_TYPE"); return INT_TYPE;} +"s" {DBG("SELECT"); return SELECT;} +"select" {DBG("SELECT"); return SELECT;} +"p" {DBG("PROJECT"); return PROJECT;} +"project" {DBG("PROJECT"); return PROJECT;} +"j" {DBG("JOIN"); return JOIN;} +"join" {DBG("JOIN"); return JOIN;} +[A-Za-z_][A-Za-z0-9_]* {DBG("IDENT"); yylval->string = strdup(yytext);return IDENT; } +[A-Za-z_][A-Za-z0-9_]* {DBG("TABLE"); yylval->string = strdup(yytext); return TABLE; } +[-+]?[0-9]+ {DBG("INT"); yylval->number = atoi(yytext); /*XXX error checking*/return INT; } +$[A-Za-z_][A-Za-z0-9_]* {DBG("COLNAME"); yylval->string = strdup(yytext+1); return COLNAME; } +$[1-9][0-9]* {DBG("COLNUM"); yylval->number = atoi(yytext+1); /*XXX*/return COLNUM; } +$0 {DBG("COLNUM"); yylval->number = 0; return COLNUM; } + +\"[^"]* {DBG("STRING"); + if (yytext[yyleng-1] == '\\') { + yymore(); + } else { + input(yyscanner); + yylval->string = strdup(yytext+1); + return STRING; + } + } +[ \t\n] DBG("WS"); +%% diff --git a/src/apps/referential/lang/parse.c b/src/apps/referential/lang/parse.c new file mode 100644 index 0000000..b1588fd --- /dev/null +++ b/src/apps/referential/lang/parse.c @@ -0,0 +1,25 @@ +#include "ast.h" +#include +#include + +int main (int argc, char * argv[]) { + char * in = 0; + size_t len = 0; + char * buf = 0; + int read; + while(-1!=(read = getline(&in, &len, stdin))) { + // printf("->%s<-",in); + // fflush(NULL); + buf = astrncat(buf,in); + } + // int ret = yyparse(); + expr_list * results = 0; + + parse(buf, &results); + if(results) { + char * str = pp_expr_list(results); + printf("%s", str); + free(str); + } + return results == 0; +} diff --git a/src/apps/referential/lang/parse.y b/src/apps/referential/lang/parse.y new file mode 100644 index 0000000..579cdd4 --- /dev/null +++ b/src/apps/referential/lang/parse.y @@ -0,0 +1,295 @@ +%{ + +#include +#include +#include + +#include "ast.h" + +#include "/home/sears/stasis/src/apps/referential/lang/parser_private.h" + + +void parse(char *buf, expr_list **result) + { + parse_parm pp; + + pp.buf = buf; + pp.length = strlen(buf); + pp.pos = 0; + *result = 0; + yylex_init(&pp.yyscanner); + yyset_extra(&pp, pp.yyscanner); + yyparse(&pp, pp.yyscanner); + *result = pp.result; + yylex_destroy(pp.yyscanner); + } + +%} + +%pure_parser +%parse-param {parse_parm *parm} +%parse-param {void *scanner} +%lex-param {yyscan_t *scanner} + + //%} + +%token LPAREN RPAREN LBRACKET RBRACKET +%token COMMA BAR STAR EQUAL +%token SELECT PROJECT JOIN +%token QUERY INSERT DELETE CREATE + +/* The reserved words "string" and "int" */ +%token STRING_TYPE +%token INT_TYPE + + + +%union { + val_entry * val_ent; + col_entry * col_ent; + cmp_entry * cmp_ent; + typ_entry * typ_ent; + val_tuple * val_tup; + col_tuple * col_tup; + cmp_tuple * cmp_tup; + typ_tuple * typ_tup; + union_typ * union_typ; + union_cmp * union_cmp; + union_qry * union_qry; + insert * ins_expr; + delete * del_expr; + query * qry_expr; + create * crt_expr; + expr * expr; + expr_list * exprs; + char * string; + int number; + enum cmp_typ comparator; +} + +%token TABLE +%token IDENT +%token COLNAME +%token COLNUM +%token STRING +%token INT + +%type val +%type col +%type cmp +%type typ +%type test + +%type val_list val_tuple +%type col_list col_tuple +%type cmp_list cmp_tuple +%type typ_list typ_tuple + +%type union_typ +%type union_cmp +%type union_qry + +%type insert +%type delete +%type query +%type create +%type expr +%type expr_list + +%% + +expr_list : expr { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; parm->result = $$; } + | expr_list expr + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $2; + } + +expr : QUERY union_qry { + $$ = malloc(sizeof(*$$)); + $$->typ = query_typ; + $$->u.q = $2; + } + | INSERT insert { + $$ = malloc(sizeof(*$$)); + $$->typ = insert_typ; + $$->u.i = $2; + } + | DELETE delete { + $$ = malloc(sizeof(*$$)); + $$->typ = delete_typ; + $$->u.d = $2; + } + | CREATE create { + $$ = malloc(sizeof(*$$)); + $$->typ = create_typ; + $$->u.c = $2; + } +union_qry : query { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; } + | union_qry BAR query + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $3; + } + +query : TABLE + { + $$ = malloc(sizeof(*$$)); $$->typ=scan_typ; + $$->u.scn = malloc(sizeof(*$$->u.scn)); + $$->u.scn->table = $1; + } + | STAR + { + $$ = malloc(sizeof(*$$)); $$->typ=table_star_typ; + $$->u.scn = 0; + } + | LBRACKET SELECT union_cmp union_qry RBRACKET + { + $$ = malloc(sizeof(*$$)); $$->typ=select_typ; + $$->u.sel = malloc(sizeof(*$$->u.sel)); + $$->u.sel->t = $3; + $$->u.sel->q = $4; + } + | LBRACKET PROJECT col_tuple union_qry RBRACKET + { + $$ = malloc(sizeof(*$$)); $$->typ=project_typ; + $$->u.prj = malloc(sizeof(*$$->u.prj)); + $$->u.prj->t = $3; + $$->u.prj->q = $4; + } + | LBRACKET JOIN cmp_tuple union_qry union_qry RBRACKET + { + $$ = malloc(sizeof(*$$)); $$->typ=join_typ; + $$->u.jn = malloc(sizeof(*$$->u.jn)); + $$->u.jn->t = $3; + $$->u.jn->lhs = $4; + $$->u.jn->rhs = $5; + }; + +insert : TABLE val_tuple { $$ = malloc(sizeof(*$$)); $$->tbl = $1; $$->t = $2; } +delete : TABLE val_tuple { $$ = malloc(sizeof(*$$)); $$->tbl = $1; $$->t = $2; } + +create : TABLE union_typ { $$ = malloc(sizeof(*$$)); $$->tbl = $1; $$->schema = $2; } + +val_tuple : LPAREN val_list RPAREN { $$ = $2; } + +val_list : val { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; } + | val_list COMMA val + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $3; + } + +val : IDENT { $$ = malloc(sizeof(*$$)); $$->typ = ident_typ; $$->u.ident = $1; } + | INT { $$ = malloc(sizeof(*$$)); $$->typ = int64_typ; $$->u.integ = $1; } + | STRING { $$ = malloc(sizeof(*$$)); $$->typ = string_typ; $$->u.str = $1; } + +col_tuple : LPAREN col_list RPAREN { $$ = $2; } + | LPAREN RPAREN { $$ = malloc(sizeof(*$$)); $$->count = 0; $$->ents = malloc(1); } + +col_list : col { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; } + | col_list COMMA col + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $3; + } + +col : COLNUM { $$ = malloc(sizeof(*$$)); $$->typ = colint_typ; $$->u.colnum = $1; } + | COLNAME { $$ = malloc(sizeof(*$$)); $$->typ = colstr_typ; $$->u.colstr = $1; } + +cmp_tuple : LPAREN cmp_list RPAREN { $$ = $2; } + | LPAREN RPAREN { $$ = malloc(sizeof(*$$)); $$->count = 0; $$->ents = malloc(sizeof(char)); } + +cmp_list : cmp { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; } + | cmp_list COMMA cmp + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $3; + } + +cmp : col test val { $$ = malloc(sizeof(*$$)); $$->lhs_typ = col_typ; $$->lhs.colent = $1; + $$->comparator = $2; + $$->rhs_typ = val_typ; $$->rhs.valent = $3; } + | val test col { $$ = malloc(sizeof(*$$)); $$->lhs_typ = val_typ; $$->lhs.valent = $1; + $$->comparator = $2; + $$->rhs_typ = col_typ; $$->rhs.colent = $3; } + | col test col { $$ = malloc(sizeof(*$$)); $$->lhs_typ = col_typ; $$->lhs.colent = $1; + $$->comparator = $2; + $$->rhs_typ = col_typ; $$->rhs.colent = $3; } + | val test val { $$ = malloc(sizeof(*$$)); $$->lhs_typ = val_typ; $$->lhs.valent = $1; + $$->comparator = $2; + $$->rhs_typ = val_typ; $$->rhs.valent = $3; } + | col { $$ = malloc(sizeof(*$$)); $$->lhs_typ = col_typ; $$->lhs.colent = $1; + $$->comparator = equal_typ; + $$->rhs_typ = col_typ; $$->rhs.colent = $1; } +| IDENT + { $$ = malloc(sizeof(*$$)); $$->lhs_typ = col_typ; $$->lhs.colent = malloc(sizeof(*$$->lhs.colent)); + $$->lhs.colent->typ=string_typ; $$->lhs.colent->u.colstr=$1; + $$->comparator = equal_typ; + $$->rhs_typ = col_typ; $$->rhs.colent = malloc(sizeof(*$$->rhs.colent)); + $$->rhs.colent->typ=string_typ; $$->rhs.colent->u.colstr=$1; } +typ_tuple : LPAREN typ_list RPAREN { $$ = $2; } +typ_list : typ { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; } + | typ_list COMMA typ + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $3; + } + +typ : STRING_TYPE + { + $$ = malloc(sizeof(*$$)); + $$->typ = typ_typ; + $$->u.type = string_typ; + } + | INT_TYPE + { + $$ = malloc(sizeof(*$$)); + $$->typ = typ_typ; + $$->u.type = int64_typ; + } + +union_typ : typ_tuple { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; } + | union_typ BAR typ_tuple + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $3; + } + +union_cmp : cmp_tuple { $$ = malloc(sizeof(*$$)); $$->count = 1; $$->ents = malloc(sizeof(*($$->ents))); $$->ents[0] = $1; } + | union_cmp BAR cmp_tuple + { + $$ = $1 ; + ($$->count)++; + $$->ents = realloc($$->ents, sizeof(*($$->ents)) * ($$->count)); + $$->ents[($$->count)-1] = $3; + } + +test : EQUAL { $$ = equal_typ; } + +%% + +int yyerror(parse_parm * param, void * yyscanner, char * errMsg) { + printf("Error: %s\n", errMsg); + // XXX memory leak? + param->result = 0; + return 0; +} +int yywrap () { return 1; } + +//#include "lex.yy.c" + diff --git a/src/apps/referential/lang/parser_private.h b/src/apps/referential/lang/parser_private.h new file mode 100644 index 0000000..186172d --- /dev/null +++ b/src/apps/referential/lang/parser_private.h @@ -0,0 +1,29 @@ +/* + From: + + http://www.usualcoding.eu/index.php?tag/flex + + */ + +typedef struct parse_parm_s +{ + void *yyscanner; + char *buf; + int pos; + int length; + void *result; +} parse_parm; + +//void parse(char *buf, expr_list **result); + + +//#define YYSTYPE + +#define YY_EXTRA_TYPE parse_parm * + +//int yylex(void /*YYSTYPE*/ *, void *); +int yylex_init(void **); +int yylex_destroy(void *); +void yyset_extra(YY_EXTRA_TYPE, void *); +int yyparse(parse_parm *, void *); +//void yyerror(); diff --git a/src/apps/referential/lang/test_parser.pl b/src/apps/referential/lang/test_parser.pl new file mode 100755 index 0000000..2576316 --- /dev/null +++ b/src/apps/referential/lang/test_parser.pl @@ -0,0 +1,92 @@ +#!/usr/bin/perl -w +use strict; + +my @winners; +my @losers; + +# +# query tests +# +my $fail = 0; + +push @winners, 'query foo'; +push @winners, 'query foo1'; +push @winners, 'query {s ($1=2,$2="asd",$3=x) foo}'; +push @winners, 'query {p ($1,$2) foo}'; +push @winners, 'query {j ($1=$4,"foo"=$3,$5=x,3=$6) foo bar}'; +push @winners, 'query {select ($1=2,$2="asd",$3=x) foo}'; +push @winners, 'query {project ($1,$2) foo}'; +push @winners, 'query {join ($1=$4,"foo"=$3,$5=x,3=$6) foo bar}'; +push @winners, 'query { + j + ($1=$4,"foo"=$3,$5=x,3=$6) + { + s ($0="a",$2=1) foo + } + bar + }'; + +push @winners, 'query {select ($3 = "blue")|($3 = 10) questions_three}'; +push @winners, 'query {project ($3){select($1="Galahad")questions_three}}'; + +push @winners, 'query {join ($MigratorID=$MigratorID) Migrators *}'; +push @winners, 'query {join ($MigratorID) Migrators { join ($BirdId) Birds *} | Fruits }'; +push @winners, 'query {join ($Type) * *}'; +push @winners, 'query {project ($titl) {select ($author="sears") {join (docid) * *}}}'; + +push @losers, 'query 1'; +push @losers, 'query foo 1'; +push @losers, 'query {p (a,2) foo}'; +push @losers, 'query {p (1,2) foo}'; +push @losers, 'query {p ("a",$2) foo}'; +push @losers, 'query {p ($1,"a") foo}'; +push @losers, 'query { + j + ($1=$4,"foo"=$3,$5=x,3=$6) + { + s ("a",*,1) foo + + bar + }'; +# +# insert tests +# + +push @winners, 'insert foo (a,"1",1)'; +push @winners, 'insert foo (a,"`1234567890-=~!@#$%^&*()+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;\\\'ASDFGHJKL:'."\n".'zxcvbnm,./ZXCVBNM<>?",1)'; + +push @winners, 'delete foo (a,"1",1)'; +push @winners, 'delete foo (a,"`1234567890-=~!@#$%^&*()+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;\\\'ASDFGHJKL:'."\n".'zxcvbnm,./ZXCVBNM<>?",1)'; + +push @losers, 'delete foo (string,"1",1)'; +push @losers, 'delete foo (int,"`1234567890-=~!@#$%^&*()+qwertyuiop[]\QWERTYUIOP{}|asdfghjkl;\\\'ASDFGHJKL:'."\n".'zxcvbnm,./ZXCVBNM<>?",1)'; + +push @winners, 'create foo (int, string, int)'; +push @losers, 'create foo'; +push @losers, 'create foo (int, string, "char")'; + +push @winners, 'create foo (int, string)|(string, int)'; + + + +foreach my $q (@winners) { + open TST, "| ./parser"; + print TST $q; + if(!close TST) { + # command failed: + print "unexpected fail: $q\n"; + $fail ++; + } +} +foreach my $q (@losers) { + open TST, "| ./parser"; + print TST $q; + if(close TST) { + # command succeeded: + print "unexpected pass: $q\n"; + $fail ++; + } +} +if($fail) { + exit(1); +} diff --git a/src/apps/referential/test-script.ref b/src/apps/referential/test-script.ref index f24de27..7681228 100644 --- a/src/apps/referential/test-script.ref +++ b/src/apps/referential/test-script.ref @@ -1,26 +1,48 @@ query query TABLES query {s (1) TABLES} +query {s ($1) TABLES} +query {s ($1=TABLES) TABLES} +query {s ($0=TABLES) TABLES} +query {s ($0="TABLES") TABLES} +query {s ($1="TABLES") TABLES} query {s (TABLES,*,*,*) TABLES} query {s (TABLES,*,*,*,*) TABLES} query {p (1,2,3,4) TABLES} +query {p ($1,$2,$3,$4) TABLES} query {p (0,1,2,3) TABLES} +query {p ($0,$1,$2,$3) TABLES} +query {p ($0,$1,$2,$100) TABLES} query {p (0,0,0,0) TABLES} -query {p (0,1,2,3,0,1,2,3,0) TABLES} +query {p ($0,$0,$0,$0) TABLES} +query {p ($0,$1,$2,$3,$0,$1,$2,$3,$0) TABLES} query {p (0,1,2,3,0,1,2,3,0) xxx} +query {p ($0,$1,$2,$3,$0,$1,$2,$3,$0) xxx} query {p (0) xxx} +query {p ($0) xxx} query {s (*) xxx} +query {s () xxx} +query {s () TABLES} query {j (1=1) xxx yyy} +query {j ($1=$1) xxx yyy} query {p (a,b,c) TABLES} query {p (0,1,2) TABLES} +query {p ($0,$1,$2) TABLES} query {s () TABLES} query {p () TABLES} query {s () {p () TABLES} } query {j () TABLES TABLES} +query {j ($0=$0) TABLES TABLES} query {j (0=0) TABLES TABLES} +query {j (0=1) TABLES TABLES} query {j (0=0,1=1) TABLES TABLES} +query {j ($0=$0,$1=$1) TABLES TABLES} query {j (0=0,1=2) TABLES TABLES} +query {j ($0=$0,$1=$2) TABLES TABLES} +query {j ($0=$0,$1=$100) TABLES TABLES} query {j (0<0) TABLES TABLES} +query {j ($0<$0) TABLES TABLES} query {x y z} create foo insert foo bar + diff --git a/src/apps/referential/toplevel.c b/src/apps/referential/toplevel.c index 061ab93..527e4ec 100644 --- a/src/apps/referential/toplevel.c +++ b/src/apps/referential/toplevel.c @@ -12,8 +12,14 @@ #include #include "algebra.h" +#include "tuple.h" +#include "ddl.h" #include "dml.h" + +#include "lang/ast.h" +//XXX#include "lang/context.h" + #define MAX_CONN_QUEUE 10 #define THREAD_POOL 20 #define SHUTDOWN_SERVER 1 @@ -36,6 +42,8 @@ char interpreterStates[THREAD_POOL]; pthread_t interpreters[THREAD_POOL]; FILE * interpreterConnections[THREAD_POOL]; +ReferentialAlgebra_context_t * context; + int openInterpreter(FILE * in, FILE * out, recordid hash); void * interpreterThread(void * arg) { @@ -112,7 +120,7 @@ int openInterpreter(FILE * in, FILE * out, recordid hash) { AUTOCOMMIT = 1; Tcommit(xid); } - } else if(!strncmp(line+1,"parseTuple",strlen("parseToken"))) { + /* } else if(!strncmp(line+1,"parseTuple",strlen("parseToken"))) { char * c = line + 1 + strlen("parseToken"); char ** toks = parseTuple(&c); for(int i = 0; toks[i]; i++) { @@ -123,7 +131,7 @@ int openInterpreter(FILE * in, FILE * out, recordid hash) { strlen("parseExpression"))) { char * c = line + 1 + strlen("parseExpression"); lladdIterator_t * it = parseExpression(xid, hash, &c); - it = 0; + it = 0; */ } else if(!strncmp(line+1,"exit",strlen("exit"))) { break; } else if(!strncmp(line+1,"shutdown",strlen("shutdown"))) { @@ -131,63 +139,51 @@ int openInterpreter(FILE * in, FILE * out, recordid hash) { break; } } else { - if(!strncmp(line,"create",strlen("create"))) { - - char * linecopy = strdup(line+strlen("create")); - char * strtoks; - char * tablename = strtok_r(linecopy, " \r\n",&strtoks); - size_t sz; - byte* delme; - - if(AUTOCOMMIT) xid = Tbegin(); - - if(-1 == (sz=ThashLookup(xid, hash, (byte*)tablename,strlen(tablename)+1,&delme))) { - fprintf(out, "Creating table %s\n", tablename); - recordid newHash = ThashCreate(xid, VARIABLE_LENGTH, VARIABLE_LENGTH); - char * tpl = tplRid(newHash); - char * insert; - asprintf(&insert, "insert TABLES %s,%s\n", tablename, tpl); - - executeInsert(xid, hash, insert); - - free(insert); - free(tpl); - } else { - fprintf(out, "Table already exists: %s\n", tablename); - free(delme); - // assert(sz == sizeof(recordid)); - } - - if(AUTOCOMMIT) Tcommit(xid); - - free(linecopy); - } else if(!strncmp(line,"query",strlen("query"))) { - char * linecopy = strdup(line+strlen("query")); - - char ** result = executeQuery(xid, hash, linecopy); - - int i = 0; - if(result) { - while(result[i]) { - fprintf(out, "%s\n", result[i]); - free(result[i]); - i++; + expr_list * results = 0; + parse(line, &results); + for(int i = 0; results && i < results->count; i++) { + expr * e = results->ents[i]; + switch(e->typ) { + case query_typ: { + lladdIterator_t * it = ReferentialAlgebra_ExecuteQuery(xid, context, e->u.q); + if(it) { + while(Titerator_next(xid,it)) { + byte * tup; + Titerator_value(xid,it, &tup); + char * tupleString = stringTuple(*(tuple_t*)tup); + fprintf(out, "%s\n", tupleString); + free(tupleString); + } + Titerator_close(xid,it); } - free(result); - } else { - fprintf(out, "query failed\n"); + } break; + case insert_typ: { + if(AUTOCOMMIT) { xid = Tbegin(); } + ReferentialDML_ExecuteInsert(xid, context, e->u.i); + if(AUTOCOMMIT) { Tcommit(xid); xid = -1;} + } break; + case delete_typ: { + if(AUTOCOMMIT) { xid = Tbegin(); } + ReferentialDML_ExecuteDelete(xid, context, e->u.d); + if(AUTOCOMMIT) { Tcommit(xid); xid = -1;} + } break; + case create_typ: { + if(AUTOCOMMIT) { xid = Tbegin(); } + ReferentialDDL_CreateTable(xid, context, e->u.c); + if(AUTOCOMMIT) { xid = Tcommit(xid); xid = -1;} + } break; + default: + abort(); } - free(linecopy); - } else if(!strncmp(line,"insert",strlen("insert"))) { - if(AUTOCOMMIT) xid = Tbegin(); - executeInsert(xid, hash, line); - if(AUTOCOMMIT) Tcommit(xid); - } else if(!strncmp(line,"delete",strlen("delete"))) { - if(AUTOCOMMIT) xid = Tbegin(); - executeDelete(xid, hash, line); - if(AUTOCOMMIT) Tcommit(xid); + } + + //XXX typecheck(context, results); + if(results) { + char * str = pp_expr_list(results); + printf("%s", str); + free(str); } else { - fprintf(out, "I don't understand...\n"); + printf("No results\n"); } } fprintf(out, "> "); @@ -318,14 +314,10 @@ int main(int argc, char * argv[]) { assert(rootEntry.page == ROOT_RECORD.page); assert(rootEntry.slot == ROOT_RECORD.slot); - hash = ThashCreate(xid, VARIABLE_LENGTH, VARIABLE_LENGTH); + hash = ReferentialAlgebra_allocContext(xid); Tset(xid, rootEntry, &hash); - char * tpl = tplRid(hash); - - ThashInsert(xid,hash,(byte*)"TABLES", strlen("TABLES")+1, (byte*)tpl, strlen(tpl)+1); - } else { printf("Opened existing store\n"); rootEntry.page = ROOT_RECORD.page; @@ -333,8 +325,11 @@ int main(int argc, char * argv[]) { rootEntry.size = sizeof(recordid); Tread(xid, rootEntry, &hash); + } + context = ReferentialAlgebra_openContext(xid,hash); + Tcommit(xid); FILE * in; diff --git a/src/apps/referential/tuple.c b/src/apps/referential/tuple.c new file mode 100644 index 0000000..e2b4932 --- /dev/null +++ b/src/apps/referential/tuple.c @@ -0,0 +1,249 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +//#include "old_algebra.h" +#include "tuple.h" +#include "lang/ast.h" + +/*char * tplRid(recordid rid) { + char * ret; + asprintf(&ret, "%d,%d,%lld", rid.page, rid.slot, (long long)rid.size); + return ret; +} +recordid ridTpl(char * tpl) { + int count; + char * freeme; + char ** tok = split(tpl, &freeme, &count, ", "); + recordid ret; + errno = 0; + assert(count == 3); + ret.page = strtol(tok[0],NULL,10); + ret.slot = strtol(tok[1],NULL,10); + ret.size = strtol(tok[2],NULL,10); + if(errno) { + perror("Couldn't parse rid"); + abort(); + } + free(freeme); + free(tok); + return ret; +} + +char ** tplDup(char ** tup) { + int i = 0; + for(; tup[i]; i++) { } // i = num non-null entries + char ** ret = malloc(sizeof(char**) * (i+1)); + ret[i] = 0; + while(i) { + i--; + ret[i] = strdup(tup[i]); + } + return ret; +} +void tplFree(char ** tup) { + for(int i = 0; tup[i]; i++) { + free(tup[i]); + } + free(tup); + }*/ + +tuple_t tupleRid(recordid rid) { + tuple_t ret; + ret.count = 3; + ret.type = malloc(sizeof(datatype_t)*3); + ret.col = malloc(sizeof(tuplecol_t)*3); + ret.type[0] = int64_typ; + ret.type[1] = int64_typ; + ret.type[2] = int64_typ; + ret.col[0].int64 = rid.page; + ret.col[1].int64 = rid.slot; + ret.col[2].int64 = rid.size; + return ret; +} +recordid ridTuple(tuple_t tup) { + recordid ret = { tup.col[0].int64, tup.col[1].int64, tup.col[2].int64 }; + return ret; +} +tuple_t tupleDup(tuple_t tup) { + tuple_t ret; + ret.count = tup.count; + ret.type = malloc(sizeof(*ret.type)*tup.count); + ret.col = malloc(sizeof(*ret.col)*tup.count); + memcpy(ret.type, tup.type, sizeof(*ret.type)*tup.count); + for(col_t i = 0; i < tup.count; i++) { + switch(ret.type[i]) { + case int64_typ: { + ret.col[i].int64 = tup.col[i].int64; + } break; + case string_typ: { + ret.col[i].string = strdup(tup.col[i].string); + } break; + default: abort(); + } + } + return ret; +} +void tupleFree(tuple_t tup) { + for(col_t i = 0; i < tup.count; i++) { + switch(tup.type[i]) { + case int64_typ: { + // nop + } break; + case string_typ: { + free(tup.col[i].string); + } break; + default: abort(); + } + } + if(tup.col) { free(tup.col); } + if(tup.type) { free(tup.type); } +} + +tuple_t tupleAlloc() { + tuple_t ret; + ret.count = 0; + ret.type = 0; + ret.col = 0; + return ret; +} + +tuple_t tupleCatInt64(tuple_t t, int64_t i) { + t.count++; + t.type = realloc(t.type,t.count * sizeof(t.type[0])); + t.col = realloc(t.col,t.count * sizeof(t.col[0])); + t.type[t.count-1] = int64_typ; + t.col[t.count-1].int64 = i; + return t; +} +tuple_t tupleCatString(tuple_t t, const char * str) { + t.count++; + t.type = realloc(t.type,t.count * sizeof(t.type[0])); + t.col = realloc(t.col,t.count * sizeof(t.col[0])); + t.type[t.count-1] = string_typ; + t.col[t.count-1].string = strdup(str); + return t; +} +tuple_t tupleCatCol(tuple_t t, tuple_t src, col_t i) { + if(src.type[i] == string_typ) { + t = tupleCatString(t, src.col[i].string); + } else if (src.type[i] == int64_typ) { + t = tupleCatInt64(t, src.col[i].int64); + } + return t; +} +tuple_t tupleCatTuple(tuple_t t, tuple_t src) { + for(int i = 0; i < src.count; i++) { + t = tupleCatCol(t, src, i); + } + return t; +} + +tuple_t tupleTail(tuple_t src, col_t start_pos) { + tuple_t t = tupleAlloc(); + for(int i = start_pos; i < src.count; i++) { + t = tupleCatCol(t, src, i); + } + return t; +} + +byte * byteTuple(tuple_t t,size_t* s) { + byte * b; + *s = sizeof(col_t) + t.count * (sizeof(datatype_t)); + for(col_t i = 0; icount; i++) { + if(v->ents[i]->typ == string_typ) { + t = tupleCatString(t, v->ents[i]->u.str); + } else if(v->ents[i]->typ == int64_typ) { + t = tupleCatInt64(t, v->ents[i]->u.integ); + } else if(v->ents[i]->typ == ident_typ) { + abort(); + } else { + abort(); + } + } + return t; +} +tuple_t tupleUnion_typ(union_typ * v) { + assert(v->count == 1); + tuple_t t = tupleAlloc(); + typ_tuple * tt = v->ents[0]; + for(int i = 0; i < tt->count; i++) { + assert(tt->ents[i]->typ == typ_typ); + t = tupleCatInt64(t, tt->ents[i]->u.type); + } + return t; +} diff --git a/src/apps/referential/tuple.h b/src/apps/referential/tuple.h new file mode 100644 index 0000000..a3818e1 --- /dev/null +++ b/src/apps/referential/tuple.h @@ -0,0 +1,51 @@ +#include "lang/ast.h" + +#ifndef TUPLE_H +#define TUPLE_H +#include +#include + +typedef uint8_t col_t; + +typedef enum { + star_typ, + ident_typ, + int64_typ, + string_typ, + colint_typ, + colstr_typ, + typ_typ, +} datatype_t; + + +typedef union { + int64_t int64; + char * string; +} tuplecol_t; +typedef struct tuple_t { + col_t count; + datatype_t * type; + tuplecol_t * col; +} tuple_t; + +tuple_t tupleRid(recordid rid); +recordid ridTuple(tuple_t tpl); + +char * stringTuple(tuple_t); +byte * byteTuple(tuple_t,size_t*); +tuple_t tupleByte(byte*); + +tuple_t tupleVal_tuple(val_tuple * t); +tuple_t tupleUnion_typ(union_typ * t); + +tuple_t tupleDup(tuple_t tup); +void tupleFree(tuple_t tup); + +tuple_t tupleAlloc(); + +tuple_t tupleCatString(tuple_t t, const char * str); +tuple_t tupleCatInt64(tuple_t t, int64_t str); +tuple_t tupleCatCol(tuple_t t, tuple_t src, col_t col); +tuple_t tupleCatTuple(tuple_t t, tuple_t src); +tuple_t tupleTail(tuple_t t, col_t start_pos); +#endif //TUPLE_H/