diff options
| author | M. Shulhan <ms@kilabit.org> | 2009-01-26 14:31:50 +0700 |
|---|---|---|
| committer | M. Shulhan <ms@kilabit.org> | 2009-01-26 14:31:50 +0700 |
| commit | 8db65208771259e7c4329de32891a5fe37bde227 (patch) | |
| tree | e78ce51fca993b70f5466669333b1764abd7c4f7 | |
| download | vos-8db65208771259e7c4329de32891a5fe37bde227.tar.xz | |
Vos
63 files changed, 6133 insertions, 0 deletions
@@ -0,0 +1,45 @@ +Copyright (C) 2009 M. Shulhan (ms@kilabit.org). All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. All advertising materials mentioning features or use of this software must + display the following acknowledgment: + "This product includes software written by M. Shulhan (ms@kilabit.org)" + +4. The names "M. Shulhan" and "Vos" must not be used to endorse or promote + products derived from this software without specific prior written + permission. + +5. Products derived from this software may not be called "Vos" nor may "Vos" + appear in their names without prior written permission of the author. + +THIS SOFTWARE IS PROVIDED BY SHULHAN "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + --- --- --- --- --- --- --- + + TT TT II BB AAAA LLLLLL II KKKKKKKK + TT TT II BB AA AA LL LL II KK + TTTT II BB AA AA LL LL II KK + TT TT II BB AAAAAAAA LLLLLL II KK + TT TT II BB AA AA LL LL II KK + TT TT II BBBBBBBB AA AA LLLLLL II KK + +Website: http://www.kilabit.org +Contact: info@kilabit.org diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6ad908c --- /dev/null +++ b/Makefile @@ -0,0 +1,68 @@ +SRC_D = . +SRC_OP_D = ${SRC_D}/op +SRC_PROC_D = ${SRC_D}/proc + +BUILD_D = ../build +BUILD_OP_D = ${BUILD_D}/op +BUILD_PROC_D = ${BUILD_D}/proc + +CC = gcc +CFLAGS = -Wall -O2 -I${SRC_D} +CFLAGS_DEBUG = -Wall -g -O0 -I${SRC_D} +LDFLAGS = -lpthread + +COMPILE = echo "[COMPILE] $@"; \ + ${CC} ${CFLAGS} -c $< -o $@ +BUILD = echo "[_BUILD_] $@"; \ + ${CC} ${CFLAGS} ${LDFLAGS} $^ -o $@ + +BIN = ${BUILD_D}/vos +VOS_OBJS = \ + ${BUILD_D}/vos_errno.o \ + ${BUILD_OP_D}/vos_String.o \ + ${BUILD_OP_D}/vos_File.o \ + ${BUILD_OP_D}/vos_LL.o \ + ${BUILD_OP_D}/vos_Filter.o \ + ${BUILD_OP_D}/vos_Field.o \ + ${BUILD_OP_D}/vos_Record.o \ + ${BUILD_OP_D}/vos_Bucket.o \ + ${BUILD_OP_D}/vos_StmtMeta.o \ + ${BUILD_OP_D}/vos_Stmt.o \ + ${BUILD_OP_D}/vos_StmtSet.o \ + ${BUILD_OP_D}/vos_StmtLoad.o \ + ${BUILD_OP_D}/vos_StmtCreate.o \ + ${BUILD_OP_D}/vos_StmtSort.o \ + ${BUILD_OP_D}/vos_StmtJoin.o \ + ${BUILD_PROC_D}/vos_parser.o \ + ${BUILD_PROC_D}/vos_set.o \ + ${BUILD_PROC_D}/vos_load.o \ + ${BUILD_PROC_D}/vos_sort_merge.o \ + ${BUILD_PROC_D}/vos_sort.o \ + ${BUILD_PROC_D}/vos_create.o \ + ${BUILD_PROC_D}/vos_join.o \ + ${BUILD_D}/vos.o + +all: clean prebuild ${BIN} + +debug: CFLAGS = ${CFLAGS_DEBUG} +debug: clean prebuild ${BIN} + +prebuild: + @mkdir -p ${BUILD_D} + @mkdir -p ${BUILD_OP_D} + @mkdir -p ${BUILD_PROC_D} + +${BIN}: ${VOS_OBJS} + @${BUILD} + +${BUILD_D}/%.o: ${SRC_D}/%.c ${SRC_D}/%.h + @${COMPILE} + +${BUILD_OP_D}/%.o: ${SRC_OP_D}/%.c ${SRC_OP_D}/%.h + @${COMPILE} + +${BUILD_PROC_D}/%.o: ${SRC_PROC_D}/%.c ${SRC_PROC_D}/%.h + @${COMPILE} +clean: + @echo "[_CLEAN_]" + @rm -f ${BIN} ${VOS_OBJS} valgrind.out *.tmp *.sort data.output diff --git a/op/vos_Bucket.c b/op/vos_Bucket.c new file mode 100644 index 0000000..f7985e2 --- /dev/null +++ b/op/vos_Bucket.c @@ -0,0 +1,433 @@ +#include "op/vos_Bucket.h" + +void bucket_print(struct Bucket *B, const int n) +{ + int i; + int empty = 1; + + if (! B) + return; + + for (i = 1; i < n; i++) { + if (! B[i].cnt) { + B[i].stat = 1; + empty++; + } else if (B[i].p == B[i].cnt) { + B[i].stat = 1; + empty++; + } else { + B[i].stat = 0; + B[i].p = B[i].cnt; + } + } + + while (empty < n) { + for (i = 1; i < n; i++) { + if (! B[i].stat) { + printf("(%2d) \"%s\"|", B[i].p->idx, + B[i].p->v->buf); + B[i].p = B[i].p->row_next; + if (B[i].p == B[i].cnt->row_last || ! B[i].p) { + empty++; + B[i].stat = 1; + B[i].p = 0; + B[i].cnt->row_last = 0; + } + } else { + printf("\"\"|"); + } + } + printf("\n"); + } +} + +/** + * @desc: + * move each field on Record 'R' into a bucket + */ +void record_to_bucket(struct Bucket *B, struct Record *R) +{ + struct Record *p = 0; + + if (! B) + return; + if (R) + R->fld_last = 0; + while (R) { + p = R; + if (! B[R->idx].cnt) { + B[R->idx].cnt = R; + B[R->idx].cnt->row_next = 0; + } else { + B[R->idx].cnt->row_last->row_next = R; + } + B[R->idx].cnt->row_last = R; + R = R->fld_next; + p->fld_next = 0; + } +} + +void bucket_empty(struct Bucket *B, const int n) +{ + int i; + + if (! B) + return; + for (i = 1; i < n; i++) { + B[i].p = B[i].cnt; + while (B[i].p) { + str_prune(B[i].p->v); + B[i].p = B[i].p->row_next; + } + } +} + +void bucket_destroy(struct Bucket *B, const int n) +{ + int i; + + if (! B) + return; + for (i = 1; i < n; i++) { + record_destroy(&B[i].cnt); + B[i].p = 0; + } +} + +static int record_write_once(struct Record *R, struct File *F, struct Field *frmt) +{ + int s; + long len = 0; + long len2 = 0; + + /* set start position */ + if (frmt->start_p) { + len = F->pos + frmt->start_p; + if (len < F->idx) { + while (F->idx > len) { + FCURC(F) = ' '; + F->idx--; + } + } else { + len2 = F->idx; + while (len2 < len) { + FCURC(F) = ' '; + F->idx++; + len2++; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + } + } + + /* write left quote */ + if (frmt->left_q) { + FCURC(F) = frmt->left_q; + if (++F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + + /* write content of Record */ + len = R->v->idx; + if (frmt->end_p) { + /* + 1, because we start from zero */ + len2 = frmt->end_p - frmt->start_p + 1; + if (frmt->left_q) + len2--; + if (frmt->right_q) + len2--; + if (len2 < len) + len = len2; + } + if ((F->idx + len) >= F->size) { + s = file_write(F); + if (s) + return s; + } + if (len > 0) { + memcpy(&FCURC(F), R->v->buf, len); + F->idx += len; + str_prune(R->v); + } + + /* write right quote */ + if (frmt->right_q) { + FCURC(F) = frmt->right_q; + F->idx++; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + + /* set end position */ + if (frmt->end_p) { + while (len < len2) { + FCURC(F) = ' '; + F->idx++; + len++; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + } + /* write separator */ + if (frmt->sep) { + FCURC(F) = frmt->sep; + F->idx++; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + + return 0; +} + +int bucket_write(struct Bucket *B, const int n, struct File *F, + struct Field *flds) +{ + int s = 0; + int i = 0; + int empty = 1; + unsigned long nrow = 0; + struct Field *pfld = 0; + struct String snon = {0, 0, "\0"}; + struct Record non = {0, 0, &snon, 0, 0, 0, 0}; + + for (i = 1; i < n; i++) { + if (! B[i].cnt) { + B[i].stat = 1; + empty++; + } else if (B[i].p == B[i].cnt) { /* p does not move */ + B[i].stat = 1; + empty++; + } else { + B[i].stat = 0; + B[i].p = B[i].cnt; + } + } + + while (empty < n) { + pfld = flds; + for (i = 1; i < n; i++) { + if (! B[i].stat) { + s = record_write_once(B[i].p, F, pfld); + if (s) + goto err; + + B[i].p = B[i].p->row_next; + if (B[i].p == B[i].cnt->row_last || (! B[i].p)) { + empty++; + B[i].stat = 1; + B[i].p = B[i].cnt; + B[i].cnt->row_last = 0; + } + } else { + s = record_write_once(&non, F, pfld); + } + pfld = pfld->next; + } + if (F->idx >= F->size) { + s = file_write(F); + if (s) + goto err; + } + FCURC(F) = CH_NEWLINE; + F->idx++; + F->pos = F->idx; + nrow++; + } + file_write(F); +err: + return s; +} + +/** + * @return: + * < -1 : rejected + * < 0 : success, accepted + * < > 0 : fail + */ +int bucket_read_filtered(struct Bucket *B, struct File *F, struct Field *_fld) +{ + int len = 0; + int flen = 0; + int s = 0; + int reject = 0; + long int start_p = 0; + struct String *str = 0; + struct Field *fld = _fld; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + return s; + } + + while (fld) { + if (fld->flag && ! reject) + str = B[fld->idx].p->v; + + /* where do we start ? */ + if (fld->start_p) { + if (start_p < fld->start_p) { + len = fld->start_p - start_p; + start_p += len; + flen = F->idx + len; + if (flen > F->size) { + len = flen - F->size; + s = file_read(F); + if (s) + goto err; + } + F->idx += len; + } + if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + + } + } + } else if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else + goto err; + } + + if (fld->end_p) { + while (start_p <= fld->end_p) { + if (fld->flag && ! reject) + str_append_c(str, FCURC(F)); + + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->right_q) { + if (fld->flag && ! reject) + s = file_fetch_until(F, str, fld->right_q); + else + s = file_skip_until(F, fld->right_q); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + + if (fld->sep) { + while (FCURC(F) != fld->sep) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->sep) { + if (fld->flag && !reject) + s = file_fetch_until(F, str, fld->sep); + else + s = file_skip_until(F, fld->sep); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else { + if (fld->flag && !reject) + s = file_fetch_until(F, str, CH_NEWLINE); + else + s = file_skip_until(F, CH_NEWLINE); + if (s) + goto err; + } + + if ((fld->flag & FFLAG_FILTER) && !reject) { + s = fld->fop(fld->fltr_rule, str->buf, + fld->fltr_v); + /* reject this record */ + if (s == 0) { + reject = 1; + /* prune later */ + } + } + + fld = fld->next; + } + if (FCURC(F) != CH_NEWLINE) { + s = file_fetch_until(F, str, CH_NEWLINE); + } + F->idx++; + + fld = _fld; + if (reject) { + /* since we don't know in which field cause the row being + * rejected, we just reset all field content here */ + s = -1; + while (fld) { + str_prune(B[fld->idx].p->v); + fld = fld->next; + } + } else { + s = 0; + /* move `p' to the next row in the bucket */ + while (fld) { + B[fld->idx].p = B[fld->idx].p->row_next; + fld = fld->next; + } + } +err: + return s; +} diff --git a/op/vos_Bucket.h b/op/vos_Bucket.h new file mode 100644 index 0000000..87e2d89 --- /dev/null +++ b/op/vos_Bucket.h @@ -0,0 +1,17 @@ +#ifndef _VOS_BUCKET_H +#define _VOS_BUCKET_H 1 + +#include "type/vos_TBucket.h" +#include "op/vos_Record.h" + +void bucket_print(struct Bucket *B, const int n); +void record_to_bucket(struct Bucket *B, struct Record *R); +void bucket_empty(struct Bucket *B, const int n); +void bucket_destroy(struct Bucket *B, const int n); + +int bucket_write(struct Bucket *B, const int n, struct File *F, + struct Field *flds); +int bucket_read_filtered(struct Bucket *B, struct File *F, + struct Field *fld); + +#endif diff --git a/op/vos_Field.c b/op/vos_Field.c new file mode 100644 index 0000000..6ec4e8b --- /dev/null +++ b/op/vos_Field.c @@ -0,0 +1,99 @@ +#include "op/vos_Field.h" + +const char *_field_type[N_FIELD_TYPE] = { + "STRING\0", + "NUMBER\0", + "DATETIME\0" +}; + +const char *_fflag_sort[N_FFLAG_SORT] = { + "\0", + "ASC\0", + "DESC\0" +}; + +/** + * @desc: + * create new Field object 'cp' by copying properties of field 'fld', + * instead of allocating new field name and date_format, this new Field + * object only reference their value from 'fld'. + * @return: + * < 0 : success. + * < E_MEM : fail, out of memory. + */ +int field_soft_copy(struct Field *fld, struct Field **cp) +{ + (*cp) = (struct Field *) calloc(1, sizeof(struct Field)); + if (! (*cp)) + return E_MEM; + + (*cp)->idx = 0; + (*cp)->flag = 0; + (*cp)->type = fld->type; + (*cp)->left_q = fld->left_q; + (*cp)->right_q = fld->right_q; + (*cp)->start_p = fld->start_p; + (*cp)->end_p = fld->end_p; + (*cp)->sep = fld->sep; + (*cp)->date_format = fld->date_format; + (*cp)->name = fld->name; + (*cp)->next = 0; + + return 0; +} + +void field_add(struct Field **fields, struct Field *f) +{ + struct Field *p = 0; + + if (! (*fields)) { + (*fields) = f; + } else { + p = (*fields); + while (p->next) + p = p->next; + p->next = f; + } +} + +void field_print(struct Field *fields) +{ + printf("(\n"); + while (fields) { + printf("\t[%2d] '%c' : %s : '%c' : %3d : %3d : '%c' : %s : %s "\ + "(%2d)\n", + fields->idx, fields->left_q, + fields->name ? fields->name : "\0", + fields->right_q, fields->start_p, fields->end_p, + fields->sep, _field_type[fields->type], + fields->date_format ? fields->date_format : "\0", + fields->flag); + if (fields->fltr_idx) { + printf("\tFILTER %d: %s (%p) %s\n", fields->fltr_idx, + _filter_rule[fields->fltr_rule], + fields->fop, + fields->fltr_v ? fields->fltr_v : "\0"); + } + fields = fields->next; + } + printf(") "); +} + +void _field_destroy(struct Field **field, const int soft) +{ + struct Field *next = 0; + + while ((*field)) { + if (! soft) { + if ((*field)->date_format) + free((*field)->date_format); + if ((*field)->name) + free((*field)->name); + } + if ((*field)->fltr_v) + free((*field)->fltr_v); + next = (*field)->next; + free((*field)); + (*field) = next; + } +} diff --git a/op/vos_Field.h b/op/vos_Field.h new file mode 100644 index 0000000..0b3fccb --- /dev/null +++ b/op/vos_Field.h @@ -0,0 +1,23 @@ +#ifndef _VOS_FIELD_H +#define _VOS_FIELD_H 1 + +#include <strings.h> +#include "type/vos_TField.h" +#include "op/vos_String.h" +#include "op/vos_Filter.h" +#include "vos.h" + +extern const char *_field_type[N_FIELD_TYPE]; +extern const char *_fflag_sort[N_FFLAG_SORT]; + +#define field_get_type_idx(T) get_token_idx(_field_type, N_FIELD_TYPE, T) + +int field_soft_copy(struct Field *fld, struct Field **cp); +void field_add(struct Field **fields, struct Field *f); +void field_print(struct Field *fields); +void _field_destroy(struct Field **fields, const int soft); + +#define field_destroy(F) _field_destroy((F),0) +#define field_soft_destroy(F) _field_destroy((F),1) + +#endif diff --git a/op/vos_File.c b/op/vos_File.c new file mode 100644 index 0000000..5d0ffee --- /dev/null +++ b/op/vos_File.c @@ -0,0 +1,251 @@ +#include "op/vos_File.h" + +/** + * @desc: + * FOPEN_RO : file not create if not exist, instead return an error + * FOPEN_WO : file will be create if not exist, and error if exist + * @return: + * < 0 : success + * < E_MEM : fail, out of memory + * < E_FILE_OPEN : fail, cannot open file 'f' + * < E_FILE_EXIST : fail, fail 'f' is exist + * < E_FILE_NOT_EXIST : fail, file 'f' is not exit + */ +int file_open(struct File **F, const char *f, int flag) +{ + int s = 0; + + (*F) = (struct File *) calloc(1, sizeof(struct File)); + if (! (*F)) + return E_MEM; + + switch (flag) { + case FOPEN_RO: + (*F)->d = open(f, O_RDONLY); + break; + case FOPEN_WO: + (*F)->size = _vos.file_buf_size; + (*F)->d = open(f, O_WRONLY | O_CREAT | O_EXCL, + S_IRUSR | S_IWUSR); + break; + } + + if ((*F)->d < 0) { + str_raw_copy(f, &_vos.e_sparm0); + + switch (errno) { + case ENOENT: + return E_FILE_NOT_EXIST; + case EEXIST: + return E_FILE_EXIST; + default: + return E_FILE_OPEN; + } + } + + (*F)->name = f; + (*F)->buf = (char *) calloc(_vos.file_buf_size, sizeof(char)); + if (! (*F)->buf) { + s = E_MEM; + file_close(F); + } + + return s; +} + +/** + * @desc: + * at first read, File size is zero. + * @return: + * < 0 : success + * < E_FILE_END : end of file + * < E_FILE_NOT_OPEN : fail, file is not open + * < E_FILE_READ : fail, error at reading file + */ +int file_read(struct File *F) +{ + if (! F) + return E_FILE_NOT_OPEN; + + if (F->size) { + F->buf = memset(F->buf, FILE_DEF_SET, F->size); + F->pos += F->size; + F->idx = 0; + } + + F->size = read(F->d, F->buf, _vos.file_buf_size); + if (F->size <= 0) { + if (F->size == 0) + return E_FILE_END; + + str_raw_copy(F->name, &_vos.e_sparm0); + return E_FILE_READ; + } + return 0; +} + +/** + * @desc: + * write contents of File buffer. + * @return: + * < 0 : success. + * < E_FILE_NOT_OPEN : fail, file is not open. + * < E_FILE_WRITE : fail, error at writing to file. + */ +int file_write(struct File *F) +{ + int s = 0; + + if (! F) + return E_FILE_NOT_OPEN; + if (! F->idx) + return 0; + + s = write(F->d, F->buf, F->idx); + if (s < 0) { + str_raw_copy(F->name, &_vos.e_sparm0); + return E_FILE_WRITE; + } + + F->buf = memset(F->buf, FILE_DEF_SET, F->size); + F->pos += F->idx; + F->idx = 0; + + return 0; +} + +/** + * @desc: + * copy File buffer, from current File index, into String 'str' until + * character 'c' is found in File buffer. + * @return: + * < 0 : success + * < !0 : fail + */ +int file_fetch_until(struct File *F, struct String *str, int c) +{ + int s = 0; + + while (F->idx < F->size && FCURC(F) != c) { + s = str_append_c(str, FCURC(F)); + if (s) + return s; + F->idx++; + } + if (F->idx >= F->size) { + s = file_read(F); + if (s == 0) + s = file_fetch_until(F, str, c); + } + return s; +} + +/** + * @desc: + * move forward File index until character 'c' is found in buffer. + * @return: + * < 0 : success + * < !0 : fail + */ +int file_skip_until(struct File *F, int c) +{ + int s = 0; + + while (F->idx < F->size && FCURC(F) != c) + F->idx++; + if (F->idx >= F->size) { + s = file_read(F); + if (s == 0) + s = file_skip_until(F, c); + } + return s; +} + +/** + * @desc: + * skip white-space character in File buffer. + * @return: + * < 0 : success + * < !0 : fail + */ +int file_skip_space(struct File *F) +{ + int s = 0; + + while (F->idx < F->size && isspace(FCURC(F))) + F->idx++; + if (F->idx >= F->size) { + s = file_read(F); + if (s == 0) + s = file_skip_space(F); + } + return s; +} + +void file_close(struct File **F) +{ + if ((*F)) { + if ((*F)->buf) + free((*F)->buf); + if ((*F)->d > 0) + close((*F)->d); + free((*F)); + (*F) = 0; + } +} + +/** + * @desc: + * get size of 'file'. + * @return: + * < 0 : success + * < E_FILE_OPEN : fail, cannot open file + * < E_FILE_SEEK : fail, cannot seek file + */ +int file_raw_get_size(const char *file, unsigned long *fsize) +{ + int fd = 0; + + fd = open(file, O_RDONLY); + if (fd < 0) { + str_raw_copy(file, &_vos.e_sparm0); + return E_FILE_OPEN; + } + + *fsize = lseek(fd, 0, SEEK_END); + if (*fsize < 0) { + str_raw_copy(file, &_vos.e_sparm0); + return E_FILE_SEEK; + } + + close(fd); + + return 0; +} + +/** + * @desc: + * check if 'file' is exist. + * @return: + * < 1 : if 'file' is exist + * < 0 : if 'file' does not exist + * < -1 : error at opening file + */ +int file_raw_is_exist(const char *file) +{ + int s = 0; + int fd = 0; + + fd = open(file, O_RDONLY); + if (fd < 0) { + if (errno != ENOENT) { + perror(file); + s = -1; + } + } else { + close(fd); + s = 1; + } + + return s; +} diff --git a/op/vos_File.h b/op/vos_File.h new file mode 100644 index 0000000..90f8a22 --- /dev/null +++ b/op/vos_File.h @@ -0,0 +1,27 @@ +#ifndef _VOS_FILE_H +#define _VOS_FILE_H 1 + +#include <fcntl.h> +#include <unistd.h> +#include <sys/stat.h> +#include "type/vos_TFile.h" +#include "vos.h" +#include "op/vos_String.h" + +#define FILE_DEF_SET ' ' + +#define FCURC(F) F->buf[F->idx] +#define FCURP(F) (F->pos + F->idx) + +int file_open(struct File **F, const char *f, int flag); +int file_read(struct File *F); +int file_write(struct File *F); +int file_fetch_until(struct File *F, struct String *str, int c); +int file_skip_until(struct File *F, int c); +int file_skip_space(struct File *F); +void file_close(struct File **F); + +int file_raw_get_size(const char *file, unsigned long *fsize); +int file_raw_is_exist(const char *file); + +#endif diff --git a/op/vos_Filter.c b/op/vos_Filter.c new file mode 100644 index 0000000..2c45e2f --- /dev/null +++ b/op/vos_Filter.c @@ -0,0 +1,129 @@ +/*** + * @desc: filter behavior: return 1 if true or 0 if false. + * + * if v operation with fltr is true + * return rule + * return !rule + * + * the return value is checked by filter caller, + * i.e by vos_Record.record_read() + * + * if (fltr(rule, v, fltr)) + * accept this record + * else + * reject this record + */ +#include "op/vos_Filter.h" + +const char *_filter_op[N_FLTR_OP] = { + "=\0", + "==\0", + "!=\0", + "!==\0", + ">\0", + "<\0", + ">=\0", + "<=\0" +}; + +const char *_filter_rule[N_FLTR_RULE] = { + "REJECT\0", + "ACCEPT\0" +}; + +const void (*_filter_f[N_FLTR_OP]) = { + fltr_eq, + fltr_eqeq, + fltr_neq, + fltr_neqeq, + fltr_more, + fltr_less, + fltr_meq, + fltr_leq +}; + +/** + * @desc: + * case not sensitive + * @return: + * < 1 : true + * < 0 : false + */ +int fltr_eq(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcasecmp(v, fltr); + if (s == 0) + return rule; + return !rule; +} + +/** + * @desc: + * case sensitive + * @return: + * < 1 : true + * < 0 : false + */ +int fltr_eqeq(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcmp(v, fltr); + if (0 == s) + return rule; + return !rule; +} + +int fltr_neq(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcasecmp(v, fltr); + if (s != 0) + return rule; + return !rule; +} + +int fltr_neqeq(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcmp(v, fltr); + if (s != 0) + return rule; + return !rule; +} + +int fltr_more(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcasecmp(v, fltr); + if (s > 0) + return rule; + return !rule; +} + +int fltr_less(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcasecmp(v, fltr); + if (s < 0) + return rule; + return !rule; +} + +int fltr_meq(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcasecmp(v, fltr); + if (s >= 0) + return rule; + return !rule; +} + +int fltr_leq(const int rule, const char *v, const char *fltr) +{ + int s; + s = strcasecmp(v, fltr); + if (s < 0) + return rule; + return !rule; +} diff --git a/op/vos_Filter.h b/op/vos_Filter.h new file mode 100644 index 0000000..cfe4a53 --- /dev/null +++ b/op/vos_Filter.h @@ -0,0 +1,25 @@ +#ifndef _VOS_FILTER_H +#define _VOS_FILTER_H 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "type/vos_TFilter.h" + +extern const char *_filter_op[N_FLTR_OP]; +extern const char *_filter_rule[N_FLTR_RULE]; +extern const void (*_filter_f[N_FLTR_OP]); + +#define op_get_idx(T) get_token_idx(_filter_op,N_FLTR_OP,T) +#define rule_get_idx(T) get_token_idx(_filter_rule,N_FLTR_RULE,T) + +int fltr_eq(const int rule, const char *v, const char *fltr); +int fltr_eqeq(const int rule, const char *v, const char *fltr); +int fltr_neq(const int rule, const char *v, const char *fltr); +int fltr_neqeq(const int rule, const char *v, const char *fltr); +int fltr_more(const int rule, const char *v, const char *fltr); +int fltr_less(const int rule, const char *v, const char *fltr); +int fltr_meq(const int rule, const char *v, const char *fltr); +int fltr_leq(const int rule, const char *v, const char *fltr); + +#endif diff --git a/op/vos_LL.c b/op/vos_LL.c new file mode 100644 index 0000000..c726cb0 --- /dev/null +++ b/op/vos_LL.c @@ -0,0 +1,82 @@ +#include "op/vos_LL.h" + +/** + * @return: + * < 0 : success + * < E_MEM : fail, out of memory + */ +int ll_add(struct LL **ll, unsigned int num, const char *str) +{ + int s = 0; + struct LL *wen = 0; + + wen = (struct LL *) calloc(1, sizeof(struct LL)); + if (! wen) + return E_MEM; + + s = str_raw_copy(str, &wen->str); + if (s) { + free(wen); + return s; + } + + wen->num = num; + + if (! (*ll)) + (*ll) = wen; + else + (*ll)->last->next = wen; + + (*ll)->last = wen; + + return 0; +} + +void ll_link(struct LL **l, struct LL *r) +{ + if (! r) + return; + + if (! (*l)) + (*l) = r; + else + (*l)->last->next = r; + + if (r->last) { + (*l)->last = r->last; + if ((*l)->last != r->last) + r->last = 0; + } else { + while (r->next) + r = r->next; + (*l)->last = r; + } +} + +void ll_print(struct LL *ll) +{ + unsigned long n; + + while (ll) { + n = ll->num; + printf("%3lu ", n); + while (ll && n == ll->num) { + printf("%s ", ll->str); + ll = ll->next; + } + printf("\n"); + } +} + +void ll_destroy(struct LL **ll) +{ + struct LL *next = 0; + + while ((*ll)) { + if ((*ll)->str) + free((*ll)->str); + next = (*ll)->next; + free((*ll)); + (*ll) = next; + } +} diff --git a/op/vos_LL.h b/op/vos_LL.h new file mode 100644 index 0000000..a4112d2 --- /dev/null +++ b/op/vos_LL.h @@ -0,0 +1,12 @@ +#ifndef _VOS_LL_H +#define _VOS_LL_H 1 + +#include "type/vos_TLL.h" +#include "op/vos_String.h" + +int ll_add(struct LL **tok, unsigned int num, const char *str); +void ll_link(struct LL **l, struct LL *r); +void ll_print(struct LL *tok); +void ll_destroy(struct LL **tok); + +#endif diff --git a/op/vos_Record.c b/op/vos_Record.c new file mode 100644 index 0000000..459b43f --- /dev/null +++ b/op/vos_Record.c @@ -0,0 +1,722 @@ +#include "op/vos_Record.h" + +/** + * @return: + * < 0 : success + * < E_MEM : fail + */ +int record_new(struct Record **R, struct Field *fld, struct String *str) +{ + (*R) = (struct Record *) calloc(1, sizeof(struct Record)); + if (! (*R)) + return E_MEM; + + (*R)->v = str; + (*R)->idx = fld->idx; + (*R)->flag = fld->flag; + + return 0; +} + +/** + * @return: + * < -1 : l < r + * < 0 : l == r + * < 1 : l > r + */ +int _record_cmp(struct Record *l, struct Record *r, const int idx) +{ + int s = 0; + struct Record *pl = l; + struct Record *pr = r; + + if (! l && ! r) + return 0; + if (! l) + return -1; + if (! r) + return 1; + + /* search for field index to compare */ + while (l && (l->idx != idx)) + l = l->fld_next; + while (r && (r->idx != idx)) + r = r->fld_next; + + if (!l || !r) + return 0; + + if (_vos.proc_cmp_case == CMP_CASE_SENSITIVE) + s = strcmp(l->v->buf, r->v->buf); + else + s = strcasecmp(l->v->buf, r->v->buf); + + if (s == 0) { + s = _record_cmp(pl, pr, idx + 1); + } else { + if (l->flag == FFLAG_SORT_DESC) { + if (s < 0) + return 1; + if (s > 0) + return -1; + } + } + return s; +} + +void record_add_field(struct Record **R, struct Record *Rfld) +{ + if (! Rfld) + return; + + if (! (*R)) + (*R) = Rfld; + else + (*R)->fld_last->fld_next = Rfld; + + (*R)->fld_last = Rfld; +} + +void record_add_row(struct Record **R, struct Record *row) +{ + if (! row) + return; + + if (! (*R)) + (*R) = row; + else + (*R)->row_last->row_next = row; + + (*R)->row_last = row; +} + +void record_prune(struct Record *R) +{ + while (R) { + if (R->v) + str_prune(R->v); + R = R->fld_next; + } +} + +void record_destroy(struct Record **R) +{ + struct Record *Rfld = 0; + struct Record *tmp = 0; + + while ((*R)) { + Rfld = (*R)->fld_next; + while (Rfld) { + if (Rfld->v) { + str_destroy(&Rfld->v); + } + tmp = Rfld->fld_next; + free(Rfld); + Rfld = tmp; + } + + if ((*R)->v) { + str_destroy(&(*R)->v); + (*R)->v = 0; + } + tmp = (*R)->row_next; + free((*R)); + (*R) = tmp; + } + + (*R) = 0; +} + +void record_print(struct Record *R) +{ + while (R) { + printf("%s|", R->v->buf); + R = R->fld_next; + } + printf("\n"); +} + +int record_write(struct Record *R, struct File *F, struct Field *_frmt) +{ + int s = 0; + int start_p = 0; + int len = 0; + int len2 = 0; + struct Record *Rfld = 0; + struct Field *frmt = 0; + + while (R) { + start_p = F->idx; + Rfld = R; + frmt = _frmt; + while (Rfld) { + /* set start position */ + if (frmt->start_p) { + len = start_p + frmt->start_p; + if (len < F->idx) { + while (F->idx > len) { + FCURC(F) = ' '; + F->idx--; + } + } else { + F->idx = start_p + len; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + } + + /* write left quote */ + if (frmt->left_q) { + FCURC(F) = frmt->left_q; + if (++F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + + /* write content of Record */ + len = Rfld->v->idx; + if (frmt->end_p) { + len2 = frmt->end_p - frmt->start_p + 1; + if (frmt->left_q) + len2--; + if (frmt->right_q) + len2--; + if (len2 < len) + len = len2; + } + if ((F->idx + len) >= F->size) { + s = file_write(F); + if (s) + return s; + } + if (len > 0) { + memcpy(&FCURC(F), Rfld->v->buf, len); + F->idx += len; + str_prune(Rfld->v); + } + + /* write right quote */ + if (frmt->right_q) { + FCURC(F) = frmt->right_q; + F->idx++; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + + /* set end position */ + if (frmt->end_p) { + while (len <= len2) { + FCURC(F) = ' '; + F->idx++; + len++; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + } + + /* write separator */ + if (frmt->sep) { + FCURC(F) = frmt->sep; + F->idx++; + if (F->idx >= F->size) { + s = file_write(F); + if (s) + return s; + } + } + + frmt = frmt->next; + Rfld = Rfld->fld_next; + } + if (F->idx >= F->size) { + s = file_write(F); + if (s) + goto err; + } + FCURC(F) = CH_NEWLINE; + F->idx++; + + R = R->row_next; + } +err: + return s; +} + +/** + * @desc: touch if you dare! + * priority in reading a record: + * - start_p > left_q + * - end_p > right_q > sep + * @return: + * < 0 : success + * < !0 : fail. and R will be NULL + */ +int record_read(struct Record **R, struct File *F, struct Field *fld) +{ + int s = 0; + int len = 0; + int flen = 0; + long int start_p = 0; + struct String *str = 0; + struct Record *Rfld = 0; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + return s; + } + + (*R) = 0; + while (fld) { + /* where do we start ? */ + if (fld->start_p) { + if (start_p < fld->start_p) { + len = fld->start_p - start_p; + start_p += len; + flen = F->idx + len; + if (flen >= F->size) { + len = flen - F->size; + s = file_read(F); + if (s) + goto err; + } + F->idx += len; + } + if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } + } else if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else + goto err; + } + + /* create string for field data */ + s = str_create(&str); + if (s) + return s; + + if (fld->end_p) { + while (start_p <= fld->end_p) { + str_append_c(str, FCURC(F)); + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->right_q) { + s = file_fetch_until(F, str, fld->right_q); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + + if (fld->sep) { + while (FCURC(F) != fld->sep) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->sep) { + s = file_fetch_until(F, str, fld->sep); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else { + s = file_fetch_until(F, str, CH_NEWLINE); + if (s) + goto err; + } + + s = record_new(&Rfld, fld, str); + if (s) + goto err; + + record_add_field(R, Rfld); + str = 0; + Rfld = 0; + fld = fld->next; + } + /* go to next row */ + if (FCURC(F) != CH_NEWLINE) { + s = file_fetch_until(F, str, CH_NEWLINE); + } + F->idx++; + return 0; +err: + str_destroy(&str); + if (s && s != E_FILE_END) + record_destroy(R); + return s; +} + +/** + * @return: + * < 0 : success + * < > 0 : fail + */ +int record_read2(struct Record *R, struct File *F, struct Field *fld) +{ + int s = 0; + int len = 0; + int flen = 0; + long int start_p = 0; + struct String *str = 0; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + return s; + } + + while (fld) { + str = R->v; + /* where do we start ? */ + if (fld->start_p) { + if (start_p < fld->start_p) { + len = fld->start_p - start_p; + start_p += len; + flen = F->idx + len; + if (flen > F->size) { + len = flen - F->size; + s = file_read(F); + if (s) + goto err; + } + F->idx += len; + } + if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + + } + } + } else if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else + goto err; + } + + if (fld->end_p) { + while (start_p <= fld->end_p) { + str_append_c(str, FCURC(F)); + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->right_q) { + s = file_fetch_until(F, str, fld->right_q); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + + if (fld->sep) { + while (FCURC(F) != fld->sep) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->sep) { + s = file_fetch_until(F, str, fld->sep); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else { + s = file_fetch_until(F, str, CH_NEWLINE); + if (s) + goto err; + } + + fld = fld->next; + R = R->fld_next; + } + /* go to next row */ + if (FCURC(F) != CH_NEWLINE) { + file_fetch_until(F, str, CH_NEWLINE); + } + F->idx++; + s = 0; +err: + return s; +} + +int record_read_filtered(struct Record **R, struct File *F, struct Field *fld) +{ + int len = 0; + int flen = 0; + int s = 0; + int reject = 0; + long int start_p = 0; + struct String *str = 0; + struct Record *Rfld = 0; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + return s; + } + + (*R) = 0; + while (fld) { + /* where do we start ? */ + if (fld->start_p) { + if (start_p < fld->start_p) { + len = fld->start_p - start_p; + start_p += len; + flen = F->idx + len; + if (flen >= F->size) { + len = flen - F->size; + s = file_read(F); + if (s) + goto err; + } + F->idx += len; + } + if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } + } else if (fld->left_q) { + if (FCURC(F) == fld->left_q) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else + goto err; + } + + if (! str) { + s = str_create(&str); + if (s) + goto err; + } + + if (fld->end_p) { + while (start_p <= fld->end_p) { + if (fld->flag && ! reject) + str_append_c(str, FCURC(F)); + + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->right_q) { + if (fld->flag && ! reject) + s = file_fetch_until(F, str, fld->right_q); + else + s = file_skip_until(F, fld->right_q); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + + if (fld->sep) { + while (FCURC(F) != fld->sep) { + F->idx++; + start_p++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + F->idx++; + start_p++; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } + } else if (fld->sep) { + if (fld->flag && !reject) + s = file_fetch_until(F, str, fld->sep); + else + s = file_skip_until(F, fld->sep); + if (s) + goto err; + + F->idx++; + start_p += str->idx + 1; + + if (F->idx >= F->size) { + s = file_read(F); + if (s) + goto err; + } + } else { + if (fld->flag && !reject) + s = file_fetch_until(F, str, CH_NEWLINE); + else + s = file_skip_until(F, CH_NEWLINE); + if (s) + goto err; + } + + if ((fld->flag & FFLAG_FILTER) && !reject) { + s = fld->fop(fld->fltr_rule, str->buf, + fld->fltr_v); + /* reject this record */ + if (s == 0) { + reject = 1; + str_prune(str); + } + } + + if (fld->flag & FFLAG_CREATE) { + if (! reject) { + s = record_new(&Rfld, fld, str); + if (s) + goto err; + + record_add_field(R, Rfld); + str = 0; + Rfld = 0; + } + } else + str_prune(str); + + fld = fld->next; + } + /* go to next row */ + if (FCURC(F) != CH_NEWLINE) { + s = file_fetch_until(F, str, CH_NEWLINE); + } + F->idx++; + s = 0; +err: + str_destroy(&str); + if ((s && s != E_FILE_END) || reject) + record_destroy(R); + return s; +} diff --git a/op/vos_Record.h b/op/vos_Record.h new file mode 100644 index 0000000..b07f920 --- /dev/null +++ b/op/vos_Record.h @@ -0,0 +1,24 @@ +#ifndef _VOS_RECORD_H +#define _VOS_RECORD_H 1 + +#include "type/vos_TRecord.h" +#include "op/vos_File.h" +#include "op/vos_Field.h" + +int record_new(struct Record **R, struct Field *fld, struct String *str); +int _record_cmp(struct Record *l, struct Record *r, const int idx); +#define record_cmp(L,R) _record_cmp(L,R,1) + +void record_add_field(struct Record **R, struct Record *Rfld); +void record_add_row(struct Record **R, struct Record *row); +void record_prune(struct Record *R); +void record_destroy(struct Record **R); +void record_print(struct Record *R); + +int record_write(struct Record *R, struct File *F, struct Field *_fld); +int record_read(struct Record **R, struct File *F, struct Field *fld); +int record_read2(struct Record *R, struct File *F, struct Field *fld); +int record_read_filtered(struct Record **R, struct File *F, + struct Field *fld); + +#endif diff --git a/op/vos_Stmt.c b/op/vos_Stmt.c new file mode 100644 index 0000000..41fc13c --- /dev/null +++ b/op/vos_Stmt.c @@ -0,0 +1,142 @@ +#include "op/vos_Stmt.h" + +const char *_stmt_type[N_STMT_TYPE] = { + "SET\0", + "LOAD\0", + "CREATE\0", + "SORT\0", + "JOIN\0" +}; + +void stmt_add(struct Stmt **stmt, struct Stmt *new_stmt) +{ + if (! (*stmt)) { + (*stmt) = new_stmt; + (*stmt)->next = 0; + (*stmt)->prev = 0; + } else { + struct Stmt *p = (*stmt); + + while (p->next) + p = p->next; + + p->next = new_stmt; + new_stmt->prev = p; + } + (*stmt)->last = new_stmt; +} + +struct Stmt * stmt_find_by_name(struct Stmt *stmt, const char *name) +{ + int s = 0; + struct Stmt *p = stmt->last; + + while (p) { + switch (p->type) { + case STMT_LOAD: + s = strcasecmp(p->in->filename, name); + if (s == 0) + return p; + + if (p->in->alias) { + s = strcasecmp(p->in->alias, name); + if (s == 0) + return p; + } + break; + + case STMT_SORT: + s = strcasecmp(p->in->filename, name); + if (s == 0) + return p; + + if (p->in->alias) { + s = strcasecmp(p->in->alias, name); + if (s == 0) + return p; + } + break; + + case STMT_CREATE: + s = strcasecmp(p->out->filename, name); + if (s == 0) + return p; + + if (p->out->alias) { + s = strcasecmp(p->out->alias, name); + if (s == 0) + return p; + } + break; + + case STMT_JOIN: + s = strcasecmp(p->out->filename, name); + if (s == 0) + return p; + + if (p->out->alias) { + s = strcasecmp(p->out->alias, name); + if (s == 0) + return p; + } + break; + } + p = p->prev; + } + + return 0; +} + +void stmt_print(struct Stmt *stmt) +{ + while (stmt) { + switch (stmt->type) { + case STMT_SET: + stmtset_print(stmt); + break; + case STMT_LOAD: + stmtload_print(stmt); + break; + case STMT_SORT: + stmtsort_print(stmt); + break; + case STMT_CREATE: + stmtcreate_print(stmt); + break; + case STMT_JOIN: + stmtjoin_print(stmt); + break; + } + stmt = stmt->next; + } +} + +void stmt_destroy(struct Stmt **stmt) +{ + struct Stmt *p = (*stmt); + struct Stmt *pnext = 0; + + while (p) { + pnext = p->next; + + switch (p->type) { + case STMT_SET: + stmtset_destroy(&p); + break; + case STMT_LOAD: + stmtload_destroy(&p); + break; + case STMT_SORT: + stmtsort_destroy(&p); + break; + case STMT_CREATE: + stmtcreate_destroy(&p); + break; + case STMT_JOIN: + stmtjoin_destroy(&p); + break; + } + p = pnext; + } + (*stmt) = 0; +} diff --git a/op/vos_Stmt.h b/op/vos_Stmt.h new file mode 100644 index 0000000..cbd589b --- /dev/null +++ b/op/vos_Stmt.h @@ -0,0 +1,19 @@ +#ifndef _VOS_STMT_H +#define _VOS_STMT_H 1 + +#include "op/vos_StmtSet.h" +#include "op/vos_StmtLoad.h" +#include "vos_StmtSort.h" +#include "vos_StmtCreate.h" +#include "vos_StmtJoin.h" + +extern const char *_stmt_type[N_STMT_TYPE]; + +#define stmt_get_type_idx(T) get_token_idx(_stmt_type, N_STMT_TYPE, T) + +void stmt_add(struct Stmt **stmt, struct Stmt *new_stmt); +struct Stmt * stmt_find_by_name(struct Stmt *stmt, const char *name); +void stmt_print(struct Stmt *stmt); +void stmt_destroy(struct Stmt **stmt); + +#endif diff --git a/op/vos_StmtCreate.c b/op/vos_StmtCreate.c new file mode 100644 index 0000000..b9719be --- /dev/null +++ b/op/vos_StmtCreate.c @@ -0,0 +1,58 @@ +#include "op/vos_StmtCreate.h" + +int stmtcreate_create(struct Stmt **create) +{ + (*create) = (struct Stmt *) calloc(1, sizeof(struct Stmt)); + if (! (*create)) + return E_MEM; + + (*create)->out = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta)); + if (! (*create)->out) { + free((*create)); + (*create) = 0; + return E_MEM; + } + (*create)->type = STMT_CREATE; + + return 0; +} + +void stmtcreate_print(struct Stmt *create) +{ + int coma = 0; + struct StmtMeta *in = 0; + + if (! create) + return; + + printf("CREATE %s \nFROM ", create->out->filename); + + in = create->in; + while (in) { + if (coma) + printf(",\n"); + printf(" %s \n", in->filename); + field_print(in->fields); + coma++; + in = in->next; + } + printf("\n"); + + field_print(create->out->fields); + + if (create->out->alias) + printf("AS %s;\n\n", create->out->alias); + else + printf(";\n\n"); +} + +void stmtcreate_destroy(struct Stmt **create) +{ + if (! (*create)) + return; + + stmtmeta_soft_destroy(&(*create)->in); + stmtmeta_destroy(&(*create)->out); + free((*create)); + (*create) = 0; +} diff --git a/op/vos_StmtCreate.h b/op/vos_StmtCreate.h new file mode 100644 index 0000000..2a86e81 --- /dev/null +++ b/op/vos_StmtCreate.h @@ -0,0 +1,11 @@ +#ifndef _VOS_STMT_CREATE_H +#define _VOS_STMT_CREATE_H 1 + +#include "type/vos_TStmt.h" +#include "op/vos_StmtMeta.h" + +int stmtcreate_create(struct Stmt **create); +void stmtcreate_print(struct Stmt *create); +void stmtcreate_destroy(struct Stmt **create); + +#endif diff --git a/op/vos_StmtJoin.c b/op/vos_StmtJoin.c new file mode 100644 index 0000000..138c42d --- /dev/null +++ b/op/vos_StmtJoin.c @@ -0,0 +1,182 @@ +#include "op/vos_StmtJoin.h" + +const char *_join_flag[N_JOIN_FLAG] = { + "\0", + "+\0", + "-\0" +}; + +const char *_join_sort_flag[N_JOIN_SORT_FLAG] = { + "\0", + "\0", + "\0", + "\0", + "UNSORTED\0", + "\0", + "\0", + "\0", + "SORTED\0" +}; + +int stmtjoin_create(struct Stmt **join) +{ + (*join) = (struct Stmt *) calloc(1, sizeof(struct Stmt)); + if (! (*join)) + return E_MEM; + + (*join)->out = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta)); + if (! (*join)->out) { + free((*join)); + (*join) = 0; + return E_MEM; + } + (*join)->type = STMT_JOIN; + return 0; +} + +int stmtjoin_init_output(struct Stmt *join) +{ + int s; + struct Field *field = 0; + struct Field *fld_new = 0; + struct String *str = 0; + struct StmtMeta *inr = 0; + + if (! join) + return 0; + + if (! join->out->filename) { + do { + s = str_raw_randomize(VOS_JOIN_OUT_FORMAT, + &join->out->filename); + if (s) + return s; + + s = file_raw_is_exist(join->out->filename); + if (s) + free(join->out->filename); + } while (s); + } else { + s = file_raw_is_exist(join->out->filename); + if (s) { + str_raw_copy(join->out->filename, &_vos.e_sparm0); + return E_FILE_EXIST; + } + } + + s = str_create(&str); + if (s) + return s; + + field = join->in->fields; + while (field) { + fld_new = (struct Field *) calloc(1, sizeof(struct Field)); + if (! fld_new) { + s = E_MEM; + goto err; + } + + fld_new->type = field->type; + fld_new->sep = '|'; + fld_new->date_format = field->date_format; + + if (join->in->alias) { + str_append(str, join->in->alias); + str_append(str, "."); + } + str_append(str, field->name); + str_detach(str, &fld_new->name); + + field_add(&join->out->fields, fld_new); + field = field->next; + } + + inr = join->in->next; + field = inr->fields; + while (field) { + fld_new = (struct Field *) calloc(1, sizeof(struct Field)); + if (! fld_new) { + s = E_MEM; + goto err; + } + + fld_new->type = field->type; + if (field->next) + fld_new->sep = '|'; + fld_new->date_format = field->date_format; + + if (inr->alias) { + str_append(str, inr->alias); + str_append(str, "."); + } + str_append(str, field->name); + str_detach(str, &fld_new->name); + + field_add(&join->out->fields, fld_new); + field = field->next; + } + s = 0; +err: + str_destroy(&str); + return s; +} + +void stmtjoin_print(struct Stmt *join) +{ + printf("JOIN %s (%2d) ", join->in->alias, join->in->flag); + field_print(join->in->fields); + + printf("WITH %s (%2d) ", join->in->next->alias, join->in->next->flag); + field_print(join->in->next->fields); + + printf("INTO %s ", join->out->filename); + field_print(join->out->fields); + + if (join->out->alias) + printf(" AS %s ;\n", join->out->alias); + else + printf(";\n"); +} + +void stmtjoin_destroy(struct Stmt **join) +{ + struct StmtMeta *inl = 0; + struct StmtMeta *inr = 0; + + if (! (*join)) + return; + + if ((*join)->in) + inl = (*join)->in; + if (inl) + inr = inl->next; + + if (inr) { + if (inr->flag & JOIN_UNSORTED) { + if (inr->filename) + free(inr->filename); + if (inr->alias) + free(inr->alias); + field_soft_destroy(&inr->fields); + free(inr); + } else + stmtmeta_soft_destroy(&(*join)->in->next); + (*join)->in->next = 0; + } + + if (inl) { + if (inl->flag & JOIN_UNSORTED) { + if (inl->filename) + free(inl->filename); + if (inl->alias) + free(inl->alias); + field_soft_destroy(&inl->fields); + free(inl); + } else + stmtmeta_soft_destroy(&(*join)->in); + } + + stmtmeta_destroy(&(*join)->out); + free((*join)); + (*join) = 0; +} diff --git a/op/vos_StmtJoin.h b/op/vos_StmtJoin.h new file mode 100644 index 0000000..a360f91 --- /dev/null +++ b/op/vos_StmtJoin.h @@ -0,0 +1,20 @@ +#ifndef _VOS_STMTJOIN_H +#define _VOS_STMTJOIN_H 1 + +#include "type/vos_TStmtJoin.h" +#include "type/vos_TStmt.h" +#include "op/vos_StmtMeta.h" +#include "op/vos_File.h" + +extern const char *_join_flag[N_JOIN_FLAG]; +extern const char *_join_sort_flag[N_JOIN_SORT_FLAG]; + +#define join_get_flag(T) get_token_idx(_join_flag, N_JOIN_FLAG, T) +#define join_get_sort_flag(T) get_token_idx(_join_sort_flag, N_JOIN_SORT_FLAG, T) + +int stmtjoin_create(struct Stmt **join); +int stmtjoin_init_output(struct Stmt *join); +void stmtjoin_print(struct Stmt *join); +void stmtjoin_destroy(struct Stmt **join); + +#endif diff --git a/op/vos_StmtLoad.c b/op/vos_StmtLoad.c new file mode 100644 index 0000000..6bfcc23 --- /dev/null +++ b/op/vos_StmtLoad.c @@ -0,0 +1,41 @@ +#include "op/vos_StmtLoad.h" + +int stmtload_create(struct Stmt **load) +{ + (*load) = (struct Stmt *) calloc(1, sizeof(struct Stmt)); + if (! (*load)) + return E_MEM; + + (*load)->in = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta)); + if (! (*load)->in) { + free((*load)); + (*load) = 0; + return E_MEM; + } + (*load)->type = STMT_LOAD; + return 0; +} + +void stmtload_print(struct Stmt *load) +{ + if (! load && !load->in) + return; + + printf("LOAD \"%s\" \n", load->in->filename); + field_print(load->in->fields); + if (load->in->alias) + printf("AS %s;\n\n", load->in->alias); + else + printf(";\n\n"); +} + +void stmtload_destroy(struct Stmt **load) +{ + if (! (*load)) + return; + + if ((*load)->in) + stmtmeta_destroy(&(*load)->in); + free((*load)); + (*load) = 0; +} diff --git a/op/vos_StmtLoad.h b/op/vos_StmtLoad.h new file mode 100644 index 0000000..2563fb6 --- /dev/null +++ b/op/vos_StmtLoad.h @@ -0,0 +1,11 @@ +#ifndef _VOS_STMTLOAD_H +#define _VOS_STMTLOAD_H 1 + +#include "type/vos_TStmt.h" +#include "op/vos_StmtMeta.h" + +int stmtload_create(struct Stmt **load); +void stmtload_destroy(struct Stmt **load); +void stmtload_print(struct Stmt *load); + +#endif diff --git a/op/vos_StmtMeta.c b/op/vos_StmtMeta.c new file mode 100644 index 0000000..09aa311 --- /dev/null +++ b/op/vos_StmtMeta.c @@ -0,0 +1,115 @@ +#include "op/vos_StmtMeta.h" + +/** + * @return: + * < !0 : success + * < 0 : fail, filename not found + */ +struct StmtMeta * stmtmeta_search_filename(struct StmtMeta *meta, + const char *str) +{ + int s; + + while (meta) { + s = strcasecmp(meta->filename, str); + if (s == 0) + return meta; + if (meta->alias) { + s = strcasecmp(meta->alias, str); + if (s == 0) + return meta; + } + meta = meta->next; + } + + return 0; +} + +/** + * @return: + * < 0 : success, fieldname found + * < E_PARSER_UNK_FIELDNAME : fail, fieldname not found + * < E_PARSER_AMB_FIELDNAME : fail, fieldname already declared + */ +int stmtmeta_search_field(struct StmtMeta *meta, const char *fldname, + struct Field **fld_r) +{ + int s; + struct Field *fld = 0; + + while (meta) { + fld = meta->fields; + while (fld) { + s = strcasecmp(fld->name, fldname); + if (s == 0) { + if ((*fld_r)) + return E_PARSER_AMB_FIELDNAME; + else + (*fld_r) = fld; + break; + } + fld = fld->next; + } + meta = meta->next; + } + + if (! (*fld_r)) + return E_PARSER_UNK_FIELDNAME; + return 0; +} + +int stmtmeta_soft_copy(struct StmtMeta *meta, struct StmtMeta **cp) +{ + int s = 0; + struct Field *fld = 0; + struct Field *fcp = 0; + + (*cp) = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta)); + if (! (*cp)) + return E_MEM; + + str_raw_copy(meta->filename, &(*cp)->filename); + str_raw_copy(meta->alias, &(*cp)->alias); + + fld = meta->fields; + while (fld) { + s = field_soft_copy(fld, &fcp); + if (s) + goto err; + + field_add(&(*cp)->fields, fcp); + fld = fld->next; + } +err: + if (s) + stmtmeta_soft_destroy(cp); + return s; +} + +void stmtmeta_add(struct StmtMeta **meta, struct StmtMeta *n) +{ + if (! (*meta)) + (*meta) = n; + else { + struct StmtMeta *p = (*meta); + while (p->next) + p = p->next; + p->next = n; + } +} + +void _stmtmeta_destroy(struct StmtMeta **meta, const int soft) +{ + if (! (*meta)) + return; + + if ((*meta)->filename) + free((*meta)->filename); + if ((*meta)->alias) + free((*meta)->alias); + if ((*meta)->fields) + _field_destroy(&(*meta)->fields, soft); + _stmtmeta_destroy(&(*meta)->next, soft); + free((*meta)); + (*meta) = 0; +} diff --git a/op/vos_StmtMeta.h b/op/vos_StmtMeta.h new file mode 100644 index 0000000..3c4ab5d --- /dev/null +++ b/op/vos_StmtMeta.h @@ -0,0 +1,18 @@ +#ifndef _VOS_STMTMETA_H +#define _VOS_STMTMETA_H 1 + +#include "type/vos_TStmtMeta.h" +#include "op/vos_Field.h" + +struct StmtMeta * stmtmeta_search_filename(struct StmtMeta *meta, + const char *str); +int stmtmeta_search_field(struct StmtMeta *meta, const char *fldname, + struct Field **fld_r); +int stmtmeta_soft_copy(struct StmtMeta *meta, struct StmtMeta **cp); +void stmtmeta_add(struct StmtMeta **meta, struct StmtMeta *n); +void _stmtmeta_destroy(struct StmtMeta **meta, const int soft); + +#define stmtmeta_destroy(M) _stmtmeta_destroy(M,0) +#define stmtmeta_soft_destroy(M) _stmtmeta_destroy(M,1) + +#endif diff --git a/op/vos_StmtSet.c b/op/vos_StmtSet.c new file mode 100644 index 0000000..d4e91e6 --- /dev/null +++ b/op/vos_StmtSet.c @@ -0,0 +1,45 @@ +#include "op/vos_StmtSet.h" + +const char *_stmt_set[N_SET] = { + "FILE_BUFFER_SIZE\0", + "PROCESS_COMPARE_CASE_SENSITIVE\0", + "PROCESS_COMPARE_CASE_NOTSENSITIVE\0", + "PROCESS_MAX\0", + "PROCESS_MAX_ROW\0" +}; + +int stmtset_create(struct Stmt **stmt) +{ + (*stmt) = (struct Stmt *) calloc(1, sizeof(struct Stmt)); + if (! (*stmt)) + return E_MEM; + + (*stmt)->set = (struct StmtSet *) calloc(1, sizeof(struct StmtSet)); + if (! (*stmt)->set) { + free((*stmt)); + return E_MEM; + } + (*stmt)->type = STMT_SET; + return 0; +} + +void stmtset_print(struct Stmt *stmt) +{ + if (stmt && stmt->set) + printf("SET %s %s;\n\n", _stmt_set[stmt->set->var_idx], + stmt->set->value ? stmt->set->value : "\0"); +} + +void stmtset_destroy(struct Stmt **stmt) +{ + if (! (*stmt)) + return; + + if ((*stmt)->set) { + if ((*stmt)->set->value) + free((*stmt)->set->value); + free((*stmt)->set); + free((*stmt)); + (*stmt) = 0; + } +} diff --git a/op/vos_StmtSet.h b/op/vos_StmtSet.h new file mode 100644 index 0000000..ea501b8 --- /dev/null +++ b/op/vos_StmtSet.h @@ -0,0 +1,17 @@ +#ifndef _VOS_STMTSET_H +#define _VOS_STMTSET_H 1 + +#include <stdio.h> +#include <stdlib.h> +#include "vos_errno.h" +#include "type/vos_TStmt.h" + +extern const char *_stmt_set[N_SET]; + +#define set_get_var_idx(T) get_token_idx(_stmt_set, N_SET, T) + +int stmtset_create(struct Stmt **stmt); +void stmtset_print(struct Stmt *stmt); +void stmtset_destroy(struct Stmt **stmt); + +#endif diff --git a/op/vos_StmtSort.c b/op/vos_StmtSort.c new file mode 100644 index 0000000..a2d4bc8 --- /dev/null +++ b/op/vos_StmtSort.c @@ -0,0 +1,111 @@ +#include "op/vos_StmtSort.h" + +int stmtsort_create(struct Stmt **sort) +{ + (*sort) = (struct Stmt *) calloc(1, sizeof(struct Stmt)); + if (! (*sort)) + return E_MEM; + + (*sort)->out = (struct StmtMeta *) calloc(1, sizeof(struct StmtMeta)); + if (! (*sort)->out) { + free((*sort)->in); + free((*sort)); + (*sort) = 0; + return E_MEM; + } + (*sort)->type = STMT_SORT; + return 0; +} + +int stmtsort_init_output(struct Stmt *sort) +{ + int s = E_MEM; + struct Field *fld_in = 0; + struct Field *fld_out = 0; + + if (! sort->out) { + sort->out = (struct StmtMeta *) calloc(1, + sizeof(struct StmtMeta)); + if (! sort->out) + return E_MEM; + } + + if (! sort->out->filename) { + do { + s = str_raw_randomize(VOS_SORT_OUT_FORMAT, + &sort->out->filename); + if (s) + return s; + + s = file_raw_is_exist(sort->out->filename); + if (s) + free(sort->out->filename); + } while (s); + } else { + /* check if file output is exist */ + s = file_raw_is_exist(sort->out->filename); + if (s) { + str_raw_copy(sort->out->filename, &_vos.e_sparm0); + return E_FILE_EXIST; + } + } + + if (! sort->out->alias) { + s = str_raw_copy(sort->in->alias, &sort->out->alias); + if (s) + return s; + } + + sort->out->flag = sort->in->flag; + + fld_in = sort->in->fields; + while (fld_in) { + fld_out = (struct Field *) calloc(1, sizeof(struct Field)); + if (! fld_out) + return E_MEM; + + fld_out->idx = fld_in->idx; + fld_out->flag = fld_in->flag; + fld_out->type = fld_in->type; + if (fld_in->next) + fld_out->sep = '|'; + fld_out->name = fld_in->name; + fld_out->date_format = fld_in->date_format; + + field_add(&sort->out->fields, fld_out); + fld_in = fld_in->next; + } + + return 0; +} + +void stmtsort_print(struct Stmt *sort) +{ + if (! sort) + return; + + printf("SORT %s ", sort->in->alias ? sort->in->alias + : sort->in->filename); + field_print(sort->in->fields); + printf(" BY \n"); + field_print(sort->out->fields); + printf(";\n\n"); +} + +void stmtsort_destroy(struct Stmt **sort) +{ + if (! (*sort)) + return; + + stmtmeta_soft_destroy(&(*sort)->in); + if ((*sort)->out) { + if ((*sort)->out->filename) + free((*sort)->out->filename); + if ((*sort)->out->alias) + free((*sort)->out->alias); + field_soft_destroy(&(*sort)->out->fields); + free((*sort)->out); + } + free((*sort)); + (*sort) = 0; +} diff --git a/op/vos_StmtSort.h b/op/vos_StmtSort.h new file mode 100644 index 0000000..e167876 --- /dev/null +++ b/op/vos_StmtSort.h @@ -0,0 +1,15 @@ +#ifndef _VOS_STMTSORT_H +#define _VOS_STMTSORT_H 1 + +#include "type/vos_TStmt.h" +#include "op/vos_File.h" +#include "op/vos_StmtMeta.h" + +#define sort_get_idx(T) get_token_idx(_fflag_sort, N_FFLAG_SORT, T) + +int stmtsort_create(struct Stmt **sort); +int stmtsort_init_output(struct Stmt *sort); +void stmtsort_print(struct Stmt *sort); +void stmtsort_destroy(struct Stmt **sort); + +#endif diff --git a/op/vos_String.c b/op/vos_String.c new file mode 100644 index 0000000..679e243 --- /dev/null +++ b/op/vos_String.c @@ -0,0 +1,209 @@ +#include "op/vos_String.h" + +const char _alnum[N_ALNUM] = { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', /* 10 */ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', /* 20 */ + 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', /* 30 */ + 'u', 'v', 'w', 'x', 'y', 'z', /* 36 */ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', /* 46 */ + 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', /* 56 */ + 'U', 'V', 'W', 'X', 'Y', 'Z' /* 62 */ +}; + +/** + * @desc: + * create a new string object. + * @return: + * < 0 : success. + * < E_MEM : fail, out of memory. + */ +int str_create(struct String **str) +{ + (*str) = (struct String *) calloc(1, sizeof(struct String)); + if (! (*str)) + return E_MEM; + + (*str)->buf = (char *) calloc(STR_DEF_LEN + 1, sizeof(char)); + if (! (*str)->buf) { + free((*str)); + (*str) = 0; + return E_MEM; + } + (*str)->len = STR_DEF_LEN; + return 0; +} + +/** + * @desc: + * append character 'c' to the end of String buffer. + * @return: + * < 0 : success. + * < E_MEM : fail, out of memory. + */ +int str_append_c(struct String *str, const int c) +{ + if (! str) + return 0; + if (str->idx == str->len) { + str->len += STR_DEF_REALLOC_LEN; + str->buf = realloc(str->buf, str->len + 1); + if (! str->buf) + return E_MEM; + } + str->buf[str->idx++] = c; + str->buf[str->idx] = '\0'; + return 0; +} + +/** + * @desc: + * append raw string 'str' to the end of String buffer. + * @return: + * < 0 : success. + * < E_MEM : fail, out of memory. + */ +int str_append(struct String *S, const char *str) +{ + int i; + int len; + + if (! S) + return 0; + if (! str) + return 0; + + len = strlen(str); + if (S->idx + len >= S->len) { + S->len += len; + S->buf = realloc(S->buf, S->len + 1); + if (! S->buf) + return E_MEM; + } + for (i = 0; i < len; i++) + S->buf[S->idx++] = str[i]; + + S->buf[S->idx] = '\0'; + + return 0; +} + +/** + * @desc: + * Attach String buffer to 'buf', and reset 'str' back to zero with + * length leave untouch. + * warning: buffer pointed by 'buf' will be lost. + * @return: + * < 0 : success, or maybe str is empty. + * < E_MEM : fail, out of memory. + */ +int str_detach(struct String *str, char **buf) +{ + if (! str) + return 0; + + (*buf) = (char *) calloc(str->idx + 1, sizeof(char)); + if (! (*buf)) + return E_MEM; + + (*buf) = memcpy((*buf), str->buf, str->idx); + str->idx = 0; + str->buf[0] = '\0'; + return 0; +} + +/** + * @desc: reset String buffer to zero + */ +void str_prune(struct String *str) +{ + if (! str) + return; + if (str->idx) { + str->idx = 0; + str->buf[0] = '\0'; + } +} + +void str_destroy(struct String **str) +{ + if ((*str)) { + if ((*str)->buf) + free((*str)->buf); + free((*str)); + (*str) = 0; + } +} + +/** + * @desc: + * copy raw string 'str' into new 'buf' + * warning: buffer pointed by 'buf' will be lost. + * @return: + * < 0 : success, or maybe str is empty. + * < E_MEM : fail, out of memory. + */ +int str_raw_copy(const char *str, char **buf) +{ + size_t l; + + if (! str) + return 0; + + if ((*buf)) + free((*buf)); + + l = strlen(str); + (*buf) = (char *) calloc(l + 1, sizeof(char)); + if (! (*buf)) + return E_MEM; + + (*buf) = memcpy((*buf), str, l); + return 0; +} + +/** + * @desc: + * replace each 'X' character on 'format' with random alphanumeric + * character. + * @return: + * < 0 : success, or maybe 'format' is empty. + * < E_MEM : fail, out of memory. + */ +int str_raw_randomize(const char *format, char **buf) +{ + int i; + + if (! format) + return 0; + + i = strlen(format); + (*buf) = (char *) calloc(i + 1, sizeof(char)); + if (! (*buf)) + return E_MEM; + + i--; + while (i >= 0) { + if (format[i] == CH_2_REPLACE) { + (*buf)[i] = _alnum[rand() % N_ALNUM]; + } else + (*buf)[i] = format[i]; + i--; + } + return 0; +} + +/** + * @desc: + * generate a hash from raw string 'str' + * @return: + * < hash : a hash value for string 'str' + */ +unsigned long str_raw_hash(char *str, unsigned long hash) +{ + while ((*str)) { + hash = *str + (hash << 6) + (hash << 16) - hash; + str++; + } + + return hash; +} diff --git a/op/vos_String.h b/op/vos_String.h new file mode 100644 index 0000000..062f388 --- /dev/null +++ b/op/vos_String.h @@ -0,0 +1,29 @@ +#ifndef _VOS_STRING_H +#define _VOS_STRING_H 1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "vos_errno.h" +#include "type/vos_TString.h" + +#define CH_NEWLINE '\n' +#define CH_2_REPLACE 'X' + +#define STR_DEF_LEN 15 +#define STR_DEF_REALLOC_LEN 15 +#define N_ALNUM 62 + +int str_create(struct String **str); +int str_append_c(struct String *str, const int c); +int str_append(struct String *S, const char *str); +int str_detach(struct String *str, char **buf); +void str_prune(struct String *str); +void str_destroy(struct String **str); + +int str_raw_copy(const char *str, char **buf); +int str_raw_randomize(const char *format, char **buf); +unsigned long str_raw_hash(char *str, unsigned long hash); + +#endif diff --git a/proc/vos_create.c b/proc/vos_create.c new file mode 100644 index 0000000..0f32de0 --- /dev/null +++ b/proc/vos_create.c @@ -0,0 +1,269 @@ +#include "proc/vos_create.h" + +static void * create_process(void *parm) +{ + int s; + unsigned long n_row = 0; + struct ProcCreate *cproc = 0; + struct File *F = 0; + struct Record *R = 0; + struct Field *fld = 0; + + cproc = (struct ProcCreate *) parm; + s = file_open(&F, cproc->in->filename, FOPEN_RO); + if (s) + goto err; + + s = file_read(F); + if (s) + goto err; + + /* phase 1: create & fill bucket */ + do { + s = record_read_filtered(&R, F, cproc->in->fields); + if (R) { + record_to_bucket(cproc->buckets, R); + n_row++; + R = 0; + } + } while (s == 0 && n_row < _vos.proc_max_row); + if (s && s != E_FILE_END) + goto err; + + /* set row last to mark the end of row */ + fld = cproc->in->fields; + while (fld) { + if (fld->idx) { + if (cproc->buckets[fld->idx].cnt) { + cproc->buckets[fld->idx].cnt->row_last = + cproc->buckets[fld->idx].cnt->row_last->row_next; + } + } + fld = fld->next; + } + + if (_vos.debug & DBG_CREATE) { + printf("child: bucket full\n"); + } + + cproc->status = CPROC_BUCKETS_FULL; + while (cproc->status == CPROC_BUCKETS_FULL) + sleep(THREAD_TIME_WAIT); + + if (cproc->status != CPROC_START) + goto out; + if (n_row < _vos.proc_max_row) + goto out; + + if (_vos.debug & DBG_CREATE) { + printf("child: bucket empty\n"); + } + + /* phase 2: + * this is where bucket is already filled with size == _vos.proc_max_row + * but empty. so we just need to fill the empty row, no need to + * malloc/create it again. + */ + n_row = 0; + do { + s = bucket_read_filtered(cproc->buckets, F, + cproc->in->fields); + if (s == 0) { + n_row++; + } else if (s > 0 && s != E_FILE_END) + goto err; + + if (n_row >= _vos.proc_max_row) { + fld = cproc->in->fields; + while (fld) { + if (fld->idx) { + cproc->buckets[fld->idx].cnt->row_last + = cproc->buckets[fld->idx].p; + } + fld = fld->next; + } + + if (_vos.debug & DBG_CREATE) { + printf("child: bucket full\n"); + } + + cproc->status = CPROC_BUCKETS_FULL; + while (cproc->status == CPROC_BUCKETS_FULL) + sleep(THREAD_TIME_WAIT); + + if (cproc->status != CPROC_START) + goto out; + + if (_vos.debug & DBG_CREATE) { + printf("child: bucket empty\n"); + } + + n_row = 0; + } + } while (s <= 0); + + if (n_row) { + fld = cproc->in->fields; + while (fld) { + if (fld->idx) { + cproc->buckets[fld->idx].cnt->row_last = + cproc->buckets[fld->idx].p; + } + fld = fld->next; + } + } +out: + s = 0; +err: + switch (s) { + case E_FILE_OPEN: + case E_FILE_NOT_EXIST: + vos_error1(s, cproc->in->filename); + break; + case E_FILE_NOT_OPEN: + case E_FILE_READ: + vos_error0(s); + break; + } + cproc->status = CPROC_DONE; + file_close(&F); + + cproc->retval = s; + return 0; +} + +int vos_process_create(struct Stmt *create) +{ + int i = 0; + int s = 0; + int n_in = 0; + int n_done = 0; + int n_bucket = 1; + struct File *F = 0; + struct StmtMeta *pin = create->in; + struct ProcCreate *cproc = 0; + struct Bucket *buckets = 0; + struct Field *fld = 0; + + /* how many input ? */ + while (pin) { + n_in++; + pin = pin->next; + } + + /* how many field output (bucket) ? */ + fld = create->out->fields; + while (fld) { + n_bucket++; + fld = fld->next; + } + + s = file_open(&F, create->out->filename, FOPEN_WO); + if (s) + goto err; + + cproc = (struct ProcCreate *) calloc(n_in, sizeof(struct ProcCreate)); + if (! cproc) { + s = E_MEM; + goto err; + } + + buckets = (struct Bucket *) calloc(n_bucket, sizeof(struct Bucket)); + if (! buckets) { + s = E_MEM; + goto err; + } + + pin = create->in; + for (i = 0; i < n_in; i++) { + cproc[i].in = pin; + cproc[i].status = CPROC_START; + cproc[i].buckets = buckets; + + pthread_create(&cproc[i].tid, 0, create_process, + (void *) &cproc[i]); + pin = pin->next; + } + + /* phase 1: create & fill bucket */ + for (i = 0; i < n_in; i++) { + /* wait until child fill the buckets */ + while (cproc[i].status == CPROC_START) + sleep(THREAD_TIME_WAIT); + + if (cproc[i].status == CPROC_DONE) { + pthread_join(cproc[i].tid, 0); + if (cproc[i].retval) { + s = cproc[i].retval; + goto err; + } + + n_done++; + cproc[i].status = CPROC_END; + } + } + + if (_vos.debug & DBG_CREATE) { + printf("parent: writing bucket\n"); + bucket_print(buckets, n_bucket); + } + s = bucket_write(buckets, n_bucket, F, create->out->fields); + if (s) + goto err; + + /* phase 2: fill the buckets */ + while (n_done < n_in) { + for (i = 0; i < n_in; i++) { + /* restart threads */ + if (cproc[i].status == CPROC_BUCKETS_FULL) + cproc[i].status = CPROC_START; + + /* wait until child fill the buckets */ + while (cproc[i].status == CPROC_START) + sleep(THREAD_TIME_WAIT); + + if (cproc[i].status == CPROC_DONE) { + pthread_join(cproc[i].tid, 0); + + /* catch error here */ + if (cproc[i].retval) { + s = cproc[i].retval; + goto err; + } + + n_done++; + cproc[i].status = CPROC_END; + } + } + + if (_vos.debug & DBG_CREATE) { + printf("parent: writing bucket\n"); + bucket_print(buckets, n_bucket); + } + s = bucket_write(buckets, n_bucket, F, create->out->fields); + if (s) + goto err; + } + +err: + if (s && cproc) { + /* cancel all thread */ + for (i = 0; i < n_in; i++) { + if (cproc[i].status == CPROC_BUCKETS_FULL) { + cproc[i].status = CPROC_DONE; + pthread_join(cproc[i].tid, + (void *) &cproc[i].retval); + } + } + } + + bucket_destroy(buckets, n_bucket); + + if (buckets) + free(buckets); + if (cproc) + free(cproc); + if (F) + file_close(&F); + return s; +} diff --git a/proc/vos_create.h b/proc/vos_create.h new file mode 100644 index 0000000..92def4e --- /dev/null +++ b/proc/vos_create.h @@ -0,0 +1,12 @@ +#ifndef _VOS_PROCESS_CREATE_H +#define _VOS_PROCESS_CREATE_H 1 + +#include <pthread.h> +#include "type/vos_TProcCreate.h" +#include "op/vos_Bucket.h" + +#define THREAD_TIME_WAIT 0.1 + +int vos_process_create(struct Stmt *create); + +#endif diff --git a/proc/vos_join.c b/proc/vos_join.c new file mode 100644 index 0000000..1da9736 --- /dev/null +++ b/proc/vos_join.c @@ -0,0 +1,244 @@ +#include "proc/vos_join.h" + +static int join_do_sort(struct Stmt *join) +{ + int s = 0; + struct Stmt *sort = 0; + struct StmtMeta *inr = join->in->next; + + if (join->in->flag & JOIN_UNSORTED) { + s = stmtsort_create(&sort); + if (s) + return s; + + join->in->next = 0; + sort->in = join->in; + + s = stmtsort_init_output(sort); + if (s) + goto err; + + s = vos_process_sort(sort); + if (s) + goto err; + + join->in = sort->out; + join->in->next = inr; + sort->out = 0; + + stmtmeta_soft_destroy(&sort->in); + } + + if (inr->flag & JOIN_UNSORTED) { + if (! sort) { + s = stmtsort_create(&sort); + if (s) + return s; + } + + sort->in = join->in->next; + + s = stmtsort_init_output(sort); + if (s) + goto err; + + s = vos_process_sort(sort); + if (s) + goto err; + + join->in->next = sort->out; + sort->out = 0; + } +err: + if (sort) + stmtsort_destroy(&sort); + return s; +} + +int vos_process_join(struct Stmt *join) +{ + int s; + struct Field *field = 0; + struct File *F = 0; + struct File *FL = 0; + struct File *FR = 0; + struct Record *rowl = 0; + struct Record *rowr = 0; + struct Record *emptyl = 0; + struct Record *emptyr = 0; + struct Record *empty = 0; + struct StmtMeta *inl = join->in; + struct StmtMeta *inr = join->in->next; + struct String *str = 0; + + /* prepare for empty fields */ + if (inl->flag & JOIN_OUTER + || inl->flag & JOIN_ANTI + || inr->flag & JOIN_ANTI) { + field = inl->fields; + while (field) { + s = str_create(&str); + if (s) + goto err; + + s = record_new(&empty, field, str); + if (s) + goto err; + + record_add_field(&emptyr, empty); + empty = 0; + str = 0; + field = field->next; + } + } + if (inr->flag & JOIN_OUTER + || inr->flag & JOIN_ANTI + || inl->flag & JOIN_ANTI) { + field = inr->fields; + while (field) { + s = str_create(&str); + if (s) + goto err; + + s = record_new(&empty, field, str); + if (s) + goto err; + + record_add_field(&emptyl, empty); + empty = 0; + str = 0; + field = field->next; + } + } + + s = join_do_sort(join); + if (s) + goto err; + + inl = join->in; + inr = join->in->next; + + s = file_open(&F, join->out->filename, FOPEN_WO); + if (s) + goto err; + + s = file_open(&FL, inl->filename, FOPEN_RO); + if (s) + goto err; + + s = file_open(&FR, inr->filename, FOPEN_RO); + if (s) + goto err; + + s = file_read(FL); + if (s) + goto err; + + s = file_read(FR); + if (s) + goto err; + + s = record_read(&rowl, FL, inl->fields); + s = record_read(&rowr, FR, inr->fields); + while (s == 0) { + s = record_cmp(rowl, rowr); + if (s < 0) { + /* x+ || x- */ + if (inl->flag & JOIN_OUTER + || inl->flag & JOIN_ANTI) { + rowl->fld_last->fld_next = emptyr; + record_write(rowl, F, join->out->fields); + rowl->fld_last->fld_next = 0; + } else { + record_prune(rowl); + } + s = record_read2(rowl, FL, inl->fields); + if (s) + break; + } else if (s == 0) { + /* x- && y- */ + if ((inl->flag & JOIN_ANTI) + && (inr->flag & JOIN_ANTI)) { + record_prune(rowl); + record_prune(rowr); + } else if (inl->flag & JOIN_ANTI) { + emptyl->fld_last->fld_next = rowr; + record_write(emptyl, F, join->out->fields); + emptyl->fld_last->fld_next = 0; + record_prune(rowl); + } else if (inr->flag & JOIN_ANTI) { + rowl->fld_last->fld_next = emptyr; + record_write(rowl, F, join->out->fields); + rowl->fld_last->fld_next = 0; + record_prune(rowr); + } else { + rowl->fld_last->fld_next = rowr; + record_write(rowl, F, join->out->fields); + rowl->fld_last->fld_next = 0; + } + + s = record_read2(rowl, FL, inl->fields); + if (s) + break; + s = record_read2(rowr, FR, inr->fields); + if (s) + break; + } else { + /* y+ || y- */ + if (inr->flag & JOIN_OUTER + || inr->flag & JOIN_ANTI) { + emptyl->fld_last->fld_next = rowr; + record_write(emptyl, F, join->out->fields); + emptyl->fld_last->fld_next = 0; + } else { + record_prune(rowr); + } + + s = record_read2(rowr, FR, inr->fields); + if (s) + break; + } + } + + if (FL->size + && ((inl->flag & JOIN_OUTER) || inl->flag & JOIN_ANTI)) { + while (FL->size) { + rowl->fld_last->fld_next = emptyr; + record_write(rowl, F, join->out->fields); + rowl->fld_last->fld_next = 0; + + s = record_read2(rowl, FL, inl->fields); + } + } + + if (FR->size + && ((inr->flag & JOIN_OUTER) || inr->flag & JOIN_ANTI)) { + while (FR->size) { + emptyl->fld_last->fld_next = rowr; + record_write(emptyl, F, join->out->fields); + emptyl->fld_last->fld_next = 0; + + s = record_read2(rowr, FR, inr->fields); + } + } + file_write(F); + s = 0; +err: + record_destroy(&rowl); + record_destroy(&rowr); + file_close(&FR); + file_close(&FL); + file_close(&F); + record_destroy(&emptyl); + record_destroy(&emptyr); + + /* remove temporary sort file */ + if (inl->flag & JOIN_UNSORTED) { + unlink(inl->filename); + } + if (inr->flag & JOIN_UNSORTED) { + unlink(inr->filename); + } + + return s; +} diff --git a/proc/vos_join.h b/proc/vos_join.h new file mode 100644 index 0000000..352e488 --- /dev/null +++ b/proc/vos_join.h @@ -0,0 +1,9 @@ +#ifndef _VOS_JOIN_H +#define _VOS_JOIN_H 1 + +#include "op/vos_StmtJoin.h" +#include "proc/vos_sort.h" + +int vos_process_join(struct Stmt *join); + +#endif diff --git a/proc/vos_load.c b/proc/vos_load.c new file mode 100644 index 0000000..af1ab0b --- /dev/null +++ b/proc/vos_load.c @@ -0,0 +1,20 @@ +#include "vos_load.h" + +/** + * @desc: + * check if file to `load' is exist. + * @return: + * < 0 : success. + * < E_FILE_NOT_EXIST : fail. + */ +int vos_process_load(struct Stmt *load) +{ + int fd = 0; + + fd = open(load->in->filename, O_RDONLY); + if (fd < 0) + return E_FILE_NOT_EXIST; + + close(fd); + return 0; +} diff --git a/proc/vos_load.h b/proc/vos_load.h new file mode 100644 index 0000000..98f08ae --- /dev/null +++ b/proc/vos_load.h @@ -0,0 +1,9 @@ +#ifndef _VOS_PROCESS_LOAD_H +#define _VOS_PROCESS_LOAD_H 1 + +#include "type/vos_TStmt.h" +#include "op/vos_File.h" + +int vos_process_load(struct Stmt *load); + +#endif diff --git a/proc/vos_parser.c b/proc/vos_parser.c new file mode 100644 index 0000000..ac57bf4 --- /dev/null +++ b/proc/vos_parser.c @@ -0,0 +1,1307 @@ +#include "proc/vos_parser.h" + +enum parsing_set_todo { + PSET_DONE = 0, + PSET_START, + PSET_VAR, + PSET_VALUE, + PSET_END +}; + +enum parsing_load_todo { + PLOAD_DONE = 0, + PLOAD_START, + PLOAD_NAME, + PLOAD_FIELD_BEGIN, + PLOAD_FIELD_END, + PLOAD_AS, + PLOAD_AS_NAME, + PLOAD_END +}; + +enum parsing_field_todo { + PFIELD_DONE = 0, + PFIELD_START, + PFIELD_LEFTQ, + PFIELD_PARENT_NAME, + PFIELD_PARENT_SEP, + PFIELD_NAME, + PFIELD_RIGHTQ, + PFIELD_STARTP, + PFIELD_ENDP, + PFIELD_TYPE, + PFIELD_DATE_FORMAT, + PFIELD_SEP, + PFIELD_END +}; + +enum parsing_sort_todo { + PSORT_DONE = 0, + PSORT_START, + PSORT_INPUT, + PSORT_BY, + PSORT_FIELD, + PSORT_ORDER, + PSORT_FIELD_SEP, + PSORT_INTO, + PSORT_AS, + PSORT_AS_VALUE, + PSORT_END +}; + +enum parsing_create_todo { + PCREATE_DONE = 0, + PCREATE_START, + PCREATE_FILENAME, + PCREATE_FROM, + PCREATE_FROM_VALUE, + PCREATE_FROM_SEP, + PCREATE_FIELD_BEGIN, + PCREATE_FIELD_END, + PCREATE_FILTER, + PCREATE_FILTER_BEGIN, + PCREATE_FILTER_END, + PCREATE_AS, + PCREATE_AS_NAME, + PCREATE_END +}; + +enum parsing_filter_todo { + PFLTR_DONE = 0, + PFLTR_START, + PFLTR_RULE, + PFLTR_PARENT_NAME, + PFLTR_PARENT_SEP, + PFLTR_FIELD_NAME, + PFLTR_OP, + PFLTR_VALUE, + PFLTR_END +}; + +enum parsing_join_todo { + PJOIN_DONE = 0, + PJOIN_START, + PJOIN_INPUT, + PJOIN_INPUT_JOIN_FLAG, + PJOIN_INPUT_SORT_FLAG, + PJOIN_INPUT_SEP, + PJOIN_INTO, + PJOIN_FIELD_BEGIN, + PJOIN_FIELD_START, + PJOIN_FIELD_L_PARENT_NAME, + PJOIN_FIELD_R_PARENT_NAME, + PJOIN_FIELD_L_PARENT_SEP, + PJOIN_FIELD_R_PARENT_SEP, + PJOIN_FIELD_L_NAME, + PJOIN_FIELD_R_NAME, + PJOIN_FIELD_OP, + PJOIN_FIELD_SEP, + PJOIN_FIELD_END, + PJOIN_AS, + PJOIN_AS_NAME, + PJOIN_END +}; + +static int stmt_get_output_from(struct StmtMeta **smeta, struct Stmt *stmt, + const char *name) +{ + int s; + struct Stmt *p = 0; + + p = stmt_find_by_name(stmt, name); + if (! p) + return E_PARSER_INV_VALUE; + + switch (p->type) { + case STMT_LOAD: + s = stmtmeta_soft_copy(p->in, smeta); + break; + case STMT_SORT: + s = stmtmeta_soft_copy(p->out, smeta); + break; + case STMT_CREATE: + s = stmtmeta_soft_copy(p->out, smeta); + break; + case STMT_JOIN: + s = stmtmeta_soft_copy(p->out, smeta); + break; + default: + s = E_PARSER_INV_STMT; + } + return s; +} + +static int parsing_SET(struct Stmt **stmt, struct LL **ptok) +{ + int s = PSET_START; + + while ((*ptok) && s != PSET_DONE) { + switch (s) { + case PSET_START: + s = stmtset_create(stmt); + if (s) + return s; + s = PSET_VAR; + break; + case PSET_VAR: + s = set_get_var_idx((*ptok)->str); + if (s < 0) { + s = E_PARSER_UNK_TOKEN; + goto err; + } + + (*stmt)->set->var_idx = s; + + if (s == SET_PROC_CMP_CASE_SENSITIVE + || s == SET_PROC_CMP_CASE_NOTSENSITIVE) + s = PSET_END; + else + s = PSET_VALUE; + break; + case PSET_VALUE: + (*stmt)->set->value = (*ptok)->str; + (*ptok)->str = 0; + s = PSET_END; + break; + case PSET_END: + if ((*ptok)->str[0] != ';') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = (*ptok)->num; + _vos.e_nparm1 = (*ptok)->str[0]; + goto err; + } + s = PSET_DONE; + break; + } + (*ptok) = (*ptok)->next; + } + if (s != PSET_DONE) { + s = E_PARSER_INV_STMT; +err: + stmtset_destroy(stmt); + } + return s; +} + +/** + * @desc: + * if mref not null, that mean we parsing field for create statement. + */ +static int parsing_FIELD(struct StmtMeta *mref, struct StmtMeta *mout, + struct LL **ptok) +{ + int idx = 1; + int s = 0; + int todo_next = 0; + struct LL *prevtok = 0; + struct Field *f = 0; + struct Field *fsearch = 0; + struct StmtMeta *pmeta = 0; + struct String *fname = 0; + + if (mref) { + s = str_create(&fname); + if (s) + goto err; + } + + s = PFIELD_START; + while ((*ptok) && s != PFIELD_DONE) { + switch (s) { + case PFIELD_START: + f = (struct Field *) calloc(1, sizeof(struct Field)); + if (! f) { + s = E_MEM; + goto err; + } + s = PFIELD_LEFTQ; + break; + + case PFIELD_LEFTQ: + switch ((*ptok)->str[0]) { + case '\'': + f->left_q = (*ptok)->str[1]; + s = PFIELD_SEP; + todo_next = PFIELD_PARENT_NAME; + break; + case ':': + s = PFIELD_PARENT_NAME; + break; + default: + s = E_PARSER_UNX_TOKEN; + goto err; + } + break; + + case PFIELD_SEP: + switch ((*ptok)->str[0]) { + case ':': + s = todo_next; + break; + case ',': + if (todo_next == PFIELD_TYPE) { + s = PFIELD_END; + continue; + } + /* if todo_next != PFIELD_TYPE that's mean + * there is an error in statement so skip it + * to 'default' */ + case ')': + if (todo_next == PFIELD_TYPE) { + s = PFIELD_END; + continue; + } + default: + s = E_PARSER_UNX_TOKEN; + goto err; + } + break; + + case PFIELD_PARENT_NAME: + if (mref) { + prevtok = (*ptok); + s = PFIELD_PARENT_SEP; + break; + } + s = PFIELD_NAME; + continue; + + case PFIELD_PARENT_SEP: + if ((*ptok)->str[0] == '.') { + pmeta = stmtmeta_search_filename(mref, + prevtok->str); + if (! pmeta) { + (*ptok) = prevtok; + s = E_PARSER_INV_VALUE; + goto err; + } + s = PFIELD_NAME; + break; + } + /* continue to below */ + pmeta = mref; + (*ptok) = prevtok; + + case PFIELD_NAME: + if (mref) { + /* search field */ + s = stmtmeta_search_field(pmeta, (*ptok)->str, + &fsearch); + if (s == E_PARSER_UNK_FIELDNAME) + goto err; + + /* create field name "x.field" */ + if (pmeta->alias) { + str_append(fname, pmeta->alias); + str_append(fname, "."); + } + str_append(fname, fsearch->name); + s = str_raw_copy(fname->buf, &f->name); + if (s) + goto err; + str_prune(fname); + } else { + /* check if field already declared */ + s = stmtmeta_search_field(mout, (*ptok)->str, + &fsearch); + if (s != E_PARSER_UNK_FIELDNAME) { + s = E_PARSER_AMB_FIELDNAME; + goto err; + } + + f->name = (*ptok)->str; + (*ptok)->str = 0; + } + s = PFIELD_SEP; + todo_next = PFIELD_RIGHTQ; + break; + + case PFIELD_RIGHTQ: + switch ((*ptok)->str[0]) { + case '\'': + f->right_q = (*ptok)->str[1]; + s = PFIELD_SEP; + todo_next = PFIELD_STARTP; + break; + case ':': + s = PFIELD_STARTP; + break; + default: + s = E_PARSER_UNX_TOKEN; + goto err; + } + break; + + case PFIELD_STARTP: + if ((*ptok)->str[0] == ':') + s = PFIELD_ENDP; + else if (isdigit((*ptok)->str[0])) { + f->start_p = strtol((*ptok)->str, 0, 0); + s = PFIELD_SEP; + todo_next = PFIELD_ENDP; + } else { + s = E_PARSER_INV_VALUE; + goto err; + } + break; + + case PFIELD_ENDP: + if (isdigit((*ptok)->str[0])) { + f->end_p = strtol((*ptok)->str, 0, 0); + if (f->end_p < f->start_p) { + s = E_PARSER_INV_POS; + goto err; + } + } else if ((*ptok)->str[0] == '\'') { + f->sep = (*ptok)->str[1]; + } else { + s = PFIELD_SEP; + todo_next = PFIELD_TYPE; + continue; + } + + s = PFIELD_SEP; + todo_next = PFIELD_TYPE; + break; + + case PFIELD_TYPE: + s = field_get_type_idx((*ptok)->str); + if (s < 0) { + s = E_PARSER_INV_VALUE; + goto err; + } + f->type = s; + if (s == FT_DATETIME) + s = PFIELD_DATE_FORMAT; + else + s = PFIELD_END; + break; + + case PFIELD_DATE_FORMAT: + if (isalpha((*ptok)->str[0])) { + f->date_format = (*ptok)->str; + (*ptok)->str = 0; + s = PFIELD_END; + break; + } + + case PFIELD_END: + if (mref) { + fsearch->idx = idx++; + fsearch->flag |= FFLAG_CREATE; + pmeta = 0; + } + fsearch = 0; + + switch ((*ptok)->str[0]) { + case ',': + s = PFIELD_START; + field_add(&mout->fields, f); + break; + case ')': + s = PFIELD_DONE; + field_add(&mout->fields, f); + break; + default: + s = E_PARSER_UNX_TOKEN; + goto err; + } + continue; + } + (*ptok) = (*ptok)->next; + } + + if (s != PFIELD_DONE) { + s = E_PARSER_INV_STMT; +err: + if (f) + field_destroy(&f); + if (mout->fields) + field_destroy(&mout->fields); + } + if (fname) + str_destroy(&fname); + return s; +} + +static int parsing_LOAD(struct Stmt **load, struct LL **ptok) +{ + int s = PLOAD_START; + + while ((*ptok) && s != PLOAD_DONE) { + switch (s) { + case PLOAD_START: + s = stmtload_create(load); + if (s) + return s; + s = PLOAD_NAME; + break; + + case PLOAD_NAME: + (*load)->in->filename = (*ptok)->str; + (*ptok)->str = 0; + s = PLOAD_FIELD_BEGIN; + break; + + case PLOAD_FIELD_BEGIN: + if ((*ptok)->str[0] != '(') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = (*ptok)->num; + _vos.e_nparm1 = (*ptok)->str[0]; + goto err; + } + s = parsing_FIELD(0, (*load)->in, ptok); + if (s) + goto err; + + case PLOAD_FIELD_END: + if ((*ptok)->str[0] != ')') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = (*ptok)->num; + _vos.e_nparm1 = (*ptok)->str[0]; + goto err; + } + s = PLOAD_AS; + break; + + case PLOAD_AS: + s = strcasecmp((*ptok)->str, "AS"); + if (s == 0) { + s = PLOAD_AS_NAME; + break; + } + case PLOAD_END: + if ((*ptok)->str[0] != ';') { + s = E_PARSER_UNX_TOKEN; + goto err; + } + s = PLOAD_DONE; + break; + + case PLOAD_AS_NAME: + (*load)->in->alias = (*ptok)->str; + (*ptok)->str = 0; + s = PLOAD_END; + break; + } + (*ptok) = (*ptok)->next; + } + + if (s != PLOAD_DONE) { + s = E_PARSER_INV_STMT; +err: + stmtload_destroy(load); + } + return s; +} + +static int parsing_SORT(struct Stmt *stmt, struct Stmt **sort, + struct LL **ptok) +{ + int idx = 1; + int s = PSORT_START; + struct StmtMeta *smeta = 0; + struct Field *fsearch = 0; + + while ((*ptok) && s != PSORT_DONE) { + switch (s) { + case PSORT_START: + s = stmtsort_create(sort); + if (s) + goto err; + s = PSORT_INPUT; + break; + + case PSORT_INPUT: + s = stmt_get_output_from(&smeta, stmt, (*ptok)->str); + if (s) + goto err; + + stmtmeta_add(&(*sort)->in, smeta); + s = PSORT_BY; + break; + + case PSORT_BY: + s = strcasecmp((*ptok)->str, "BY"); + if (s) { + s = E_PARSER_INV_STMT; + goto err; + } + s = PSORT_FIELD; + break; + + case PSORT_FIELD: + s = stmtmeta_search_field(smeta, (*ptok)->str, + &fsearch); + if (s == E_PARSER_UNK_FIELDNAME) + goto err; + + s = PSORT_ORDER; + break; + + case PSORT_ORDER: + s = sort_get_idx((*ptok)->str); + if (s > 0) { + fsearch->flag = s; + s = PSORT_FIELD_SEP; + break; + } else + fsearch->flag = FFLAG_SORT_ASC; + /* go below */ + + case PSORT_FIELD_SEP: + fsearch->idx = idx++; + fsearch = 0; + if ((*ptok)->str[0] == ',') { + s = PSORT_FIELD; + break; + } + + s = strcasecmp((*ptok)->str, "INTO"); + if (s == 0) { + s = PSORT_INTO; + break; + } + /* go below */ + + case PSORT_AS: + s = strcasecmp((*ptok)->str, "AS"); + if (s == 0) { + s = PSORT_AS_VALUE; + break; + } + /* go below */ + + case PSORT_END: + if ((*ptok)->str[0] == ';') { + s = PSORT_DONE; + } else { + s = E_PARSER_UNK_TOKEN; + goto err; + } + break; + + case PSORT_INTO: + (*sort)->out->filename = (*ptok)->str; + (*ptok)->str = 0; + s = PSORT_AS; + break; + + case PSORT_AS_VALUE: + (*sort)->out->alias = (*ptok)->str; + (*ptok)->str = 0; + s = PSORT_END; + break; + } + (*ptok) = (*ptok)->next; + } + + if (s == PSORT_DONE) + s = stmtsort_init_output((*sort)); + else + s = E_PARSER_INV_STMT; +err: + if (s) { + stmtsort_destroy(sort); + } + return s; +} + +/** + * @return: + * < 0 : success + * < !0 : fail + */ +static int parsing_FILTER(struct StmtMeta *mref, struct LL **ptok) +{ + int s = PFLTR_START; + int fltr_rule = 0; + int fltr_idx = 1; + struct LL *prevtok = 0; + struct StmtMeta *pmeta = 0; + struct Field *fsearch = 0; + + while ((*ptok) && s != PFLTR_DONE) { + switch (s) { + case PFLTR_START: /* needed, so we can check next ptok */ + s = PFLTR_RULE; + break; + + case PFLTR_RULE: + fltr_rule = rule_get_idx((*ptok)->str); + if (fltr_rule < 0) { + s = E_PARSER_INV_STMT; + goto err; + } + s = PFLTR_PARENT_NAME; + break; + + case PFLTR_PARENT_NAME: + prevtok = (*ptok); + s = PFLTR_PARENT_SEP; + break; + + case PFLTR_PARENT_SEP: + if ((*ptok)->str[0] == '.') { + pmeta = stmtmeta_search_filename(mref, + prevtok->str); + if (! pmeta) { + s = E_PARSER_INV_VALUE; + goto err; + } + s = PFLTR_FIELD_NAME; + break; + } else { + s = stmtmeta_search_field(mref, prevtok->str, + &fsearch); + if (s == E_PARSER_UNK_FIELDNAME) + goto err; + + s = PFLTR_OP; + continue; + } + + case PFLTR_FIELD_NAME: + s = stmtmeta_search_field(pmeta, (*ptok)->str, + &fsearch); + if (s == E_PARSER_UNK_FIELDNAME) + goto err; + s = PFLTR_OP; + break; + + case PFLTR_OP: + s = op_get_idx((*ptok)->str); + if (s < 0) { + s = E_PARSER_UNK_TOKEN; + goto err; + } + fsearch->fop = _filter_f[s]; + s = PFLTR_VALUE; + break; + + case PFLTR_VALUE: + fsearch->fltr_v = (*ptok)->str; + (*ptok)->str = 0; + s = PFLTR_END; + break; + + case PFLTR_END: + fsearch->flag |= FFLAG_FILTER; + fsearch->fltr_idx = fltr_idx++; + fsearch->fltr_rule = fltr_rule; + fsearch = 0; + pmeta = 0; + + if ((*ptok)->str[0] == ')') { + s = PFLTR_DONE; + continue; + } + if ((*ptok)->str[0] == ',') { + s = PFLTR_START; + continue; + } + + s = E_PARSER_UNX_TOKEN; + goto err; + } + (*ptok) = (*ptok)->next; + } + + if (s != PFLTR_DONE) + s = E_PARSER_INV_STMT; +err: + return s; +} + +static int parsing_CREATE(struct Stmt *stmt, struct Stmt **create, + struct LL **ptok) +{ + int s = PCREATE_START; + struct StmtMeta *smeta = 0; + + while ((*ptok) && s != PCREATE_DONE) { + switch (s) { + case PCREATE_START: + s = stmtcreate_create(create); + if (s) + return s; + s = PCREATE_FILENAME; + break; + + case PCREATE_FILENAME: + (*create)->out->filename = (*ptok)->str; + (*ptok)->str = 0; + s = PCREATE_FROM; + break; + + case PCREATE_FROM: + s = strcasecmp((*ptok)->str, "FROM"); + if (s) { + s = E_PARSER_INV_STMT; + goto err; + } + s = PCREATE_FROM_VALUE; + break; + + case PCREATE_FROM_VALUE: + s = stmt_get_output_from(&smeta, stmt, (*ptok)->str); + if (s) + goto err; + + stmtmeta_add(&(*create)->in, smeta); + smeta = 0; + s = PCREATE_FROM_SEP; + break; + + case PCREATE_FROM_SEP: + if ((*ptok)->str[0] == ',') { + s = PCREATE_FROM_VALUE; + break; + } + + case PCREATE_FIELD_BEGIN: + if ((*ptok)->str[0] != '(') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = (*ptok)->num; + _vos.e_nparm1 = (*ptok)->str[0]; + goto err; + } + s = parsing_FIELD((*create)->in, (*create)->out, ptok); + if (s) + goto err; + + case PCREATE_FIELD_END: + if ((*ptok)->str[0] != ')') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = (*ptok)->num; + _vos.e_nparm1 = (*ptok)->str[0]; + goto err; + } + s = PCREATE_FILTER; + break; + + case PCREATE_FILTER: + s = strcasecmp((*ptok)->str, "FILTER"); + if (s == 0) { + s = PCREATE_FILTER_BEGIN; + break; + } + + case PCREATE_AS: + s = strcasecmp((*ptok)->str, "AS"); + if (s == 0) { + s = PCREATE_AS_NAME; + break; + } + + case PCREATE_END: + if ((*ptok)->str[0] != ';') { + s = E_PARSER_UNX_TOKEN; + goto err; + } + s = PCREATE_DONE; + break; + + case PCREATE_FILTER_BEGIN: + if ((*ptok)->str[0] != '(') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = (*ptok)->num; + _vos.e_nparm1 = (*ptok)->str[0]; + goto err; + } + s = parsing_FILTER((*create)->in, ptok); + if (s) + goto err; + + case PCREATE_FILTER_END: + if ((*ptok)->str[0] != ')') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = (*ptok)->num; + _vos.e_nparm1 = (*ptok)->str[0]; + goto err; + } + s = PCREATE_AS; + break; + + case PCREATE_AS_NAME: + (*create)->out->alias = (*ptok)->str; + (*ptok)->str = 0; + s = PCREATE_END; + break; + } + (*ptok) = (*ptok)->next; + } + + if (s != PCREATE_DONE) { + s = E_PARSER_INV_STMT; +err: + stmtcreate_destroy(create); + } + return s; + +} + +static int parsing_JOIN_where(struct StmtMeta *mref, struct LL **ptok) +{ + int s = 0; + int todo = PJOIN_FIELD_START; + int join_idx = 1; + struct LL *prevtok = 0; + struct StmtMeta *pmeta = 0; + struct Field *fsearch = 0; + + while ((*ptok) && todo != PJOIN_FIELD_END) { + switch (todo) { + case PJOIN_FIELD_START: + todo = PJOIN_FIELD_L_PARENT_NAME; + break; + + case PJOIN_FIELD_L_PARENT_NAME: + case PJOIN_FIELD_R_PARENT_NAME: + prevtok = (*ptok); + if (todo == PJOIN_FIELD_L_PARENT_NAME) + todo = PJOIN_FIELD_L_PARENT_SEP; + else + todo = PJOIN_FIELD_R_PARENT_SEP; + break; + + case PJOIN_FIELD_L_PARENT_SEP: + case PJOIN_FIELD_R_PARENT_SEP: + if ((*ptok)->str[0] == '.') { + pmeta = stmtmeta_search_filename(mref, + prevtok->str); + if (! pmeta) { + s = E_PARSER_INV_VALUE; + goto err; + } + if (todo == PJOIN_FIELD_L_PARENT_SEP) + todo = PJOIN_FIELD_L_NAME; + else + todo = PJOIN_FIELD_R_NAME; + } else { + s = stmtmeta_search_field(mref, prevtok->str, + &fsearch); + if (s == E_PARSER_UNK_FIELDNAME) + goto err; + + if (todo == PJOIN_FIELD_L_PARENT_SEP) + todo = PJOIN_FIELD_OP; + else + todo = PJOIN_FIELD_SEP; + continue; + } + break; + + case PJOIN_FIELD_L_NAME: + case PJOIN_FIELD_R_NAME: + s = stmtmeta_search_field(pmeta, (*ptok)->str, + &fsearch); + if (s == E_PARSER_UNK_FIELDNAME) + goto err; + if (todo == PJOIN_FIELD_L_NAME) + todo = PJOIN_FIELD_OP; + else + todo = PJOIN_FIELD_SEP; + break; + + case PJOIN_FIELD_OP: + s = op_get_idx((*ptok)->str); + if (s < OP_EQUAL || s > OP_TRUE_EQUAL) { + s = E_PARSER_INV_VALUE; + goto err; + } + fsearch->idx = join_idx; + fsearch->flag |= FFLAG_JOIN; + fsearch->fop = _filter_f[s]; + fsearch = 0; + pmeta = 0; + todo = PJOIN_FIELD_R_PARENT_NAME; + break; + + case PJOIN_FIELD_SEP: + fsearch->idx |= join_idx; + fsearch->flag |= FFLAG_JOIN; + join_idx = join_idx << 1; + fsearch = 0; + pmeta = 0; + if ((*ptok)->str[0] == ',') { + todo = PJOIN_FIELD_START; + continue; + } + if ((*ptok)->str[0] == ')') { + todo = PJOIN_FIELD_END; + continue; + } + s = E_PARSER_UNK_TOKEN; + goto err; + } + (*ptok) = (*ptok)->next; + } + return 0; +err: + return s; +} + +static int parsing_JOIN(struct Stmt *stmt, struct Stmt **join, + struct LL **ptok) +{ + int s = PJOIN_START; + int n_input = 1; + struct StmtMeta *smeta = 0; + + while ((*ptok) && s != PJOIN_DONE) { + switch (s) { + case PJOIN_START: + s = stmtjoin_create(join); + if (s) + return s; + + s = PJOIN_INPUT; + break; + + case PJOIN_INPUT: + if (n_input > 2) { + s = E_PARSER_INV_STMT; + goto err; + } + + s = stmt_get_output_from(&smeta, stmt, (*ptok)->str); + if (s) + goto err; + + stmtmeta_add(&(*join)->in, smeta); + s = PJOIN_INPUT_JOIN_FLAG; + break; + + case PJOIN_INPUT_JOIN_FLAG: + s = join_get_flag((*ptok)->str); + if (s > 0) { + smeta->flag |= s; + s = PJOIN_INPUT_SORT_FLAG; + break; + } + + case PJOIN_INPUT_SORT_FLAG: + s = join_get_sort_flag((*ptok)->str); + if (s > 0) { + smeta->flag |= s; + s = PJOIN_INPUT_SEP; + break; + } else { + smeta->flag |= JOIN_UNSORTED; + } + + case PJOIN_INPUT_SEP: + if ((*ptok)->str[0] == ',') { + n_input++; + s = PJOIN_INPUT; + smeta = 0; + break; + } + + s = strcasecmp((*ptok)->str, "INTO"); + if (s == 0) { + s = PJOIN_INTO; + break; + } + + case PJOIN_FIELD_BEGIN: + if ((*ptok)->str[0] == '(') { + if (n_input != 2) { + s = E_PARSER_INV_STMT; + goto err; + } + + s = parsing_JOIN_where((*join)->in, ptok); + if (s) + goto err; + + s = PJOIN_FIELD_END; + continue; + } + s = E_PARSER_UNK_TOKEN; + goto err; + + case PJOIN_FIELD_END: + if ((*ptok)->str[0] == ')') { + s = PJOIN_AS; + break; + } + s = E_PARSER_UNK_TOKEN; + goto err; + + case PJOIN_AS: + s = strcasecmp((*ptok)->str, "AS"); + if (s == 0) { + s = PJOIN_AS_NAME; + break; + } + + case PJOIN_END: + if ((*ptok)->str[0] == ';') { + s = PJOIN_DONE; + break; + } + s = E_PARSER_UNK_TOKEN; + goto err; + + case PJOIN_INTO: + (*join)->out->filename = (*ptok)->str; + (*ptok)->str = 0; + s = PJOIN_FIELD_BEGIN; + break; + + case PJOIN_AS_NAME: + (*join)->out->alias = (*ptok)->str; + (*ptok)->str = 0; + s = PJOIN_END; + break; + } + (*ptok) = (*ptok)->next; + } + if (s == PJOIN_DONE) { + s = stmtjoin_init_output((*join)); + } else + s = E_PARSER_INV_STMT; +err: + if (s) + stmtjoin_destroy(join); + + return s; +} + +/** + * @return: + * < 0 : success + * < -1 : fail + */ +static int parsing_token(struct Stmt **stmt, struct LL **ptok) +{ + int s = 0; + int stmt_type = 0; + struct Stmt *new_stmt = 0; + + while ((*ptok)) { + stmt_type = stmt_get_type_idx((*ptok)->str); + if (stmt_type < 0) + return E_PARSER_UNK_TOKEN; + + switch (stmt_type) { + case STMT_SET: + s = parsing_SET(&new_stmt, ptok); + break; + case STMT_LOAD: + s = parsing_LOAD(&new_stmt, ptok); + break; + case STMT_SORT: + s = parsing_SORT((*stmt), &new_stmt, ptok); + break; + case STMT_CREATE: + s = parsing_CREATE((*stmt), &new_stmt, ptok); + break; + case STMT_JOIN: + s = parsing_JOIN((*stmt), &new_stmt, ptok); + break; + default: + return E_PARSER_UNX_TOKEN; + } + if (s) + goto err; + stmt_add(stmt, new_stmt); + } + s = 0; +err: + return s; +} + +int vos_parsing(struct Stmt **stmt, const char *script) +{ + int s = 0; + unsigned int line_no = 1; + struct String *str = 0; + struct File *F = 0; + struct LL *ls_tok = 0; + struct LL *ptok = 0; + + s = file_open(&F, script, FOPEN_RO); + if (s) + goto err; + + s = file_read(F); + if (s) + goto err; + + s = str_create(&str); + if (s) + goto err; + + while (F->idx < F->size) { + switch (FCURC(F)) { + case CH_NEWLINE: + line_no++; + case ' ': case '\b': case '\f': case '\r': case '\t': + case '\v': + break; + + case '#': + s = file_skip_until(F, CH_NEWLINE); + if (s) + goto err; + + line_no++; + break; + + case '(': case ')': case ':': case ',': case ';': case '.': + case '+': case '-': + s = str_append_c(str, FCURC(F)); + if (s) + goto err; + + s = ll_add(&ls_tok, line_no, str->buf); + if (s) + goto err; + + str_prune(str); + break; + + case '!': case '=': case '<': case '>': + do { + s = str_append_c(str, FCURC(F)); + if (s) + goto err; + F->idx++; + if (F->idx >= F->size) { + s = file_read(F); + if (s) + break; + } + } while (FCURC(F) == '='); + + s = ll_add(&ls_tok, line_no, str->buf); + if (s) + goto err; + + str_prune(str); + continue; + + case '[': + F->idx++; + file_fetch_until(F, str, ']'); + if (FCURC(F) != ']') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = line_no; + _vos.e_nparm1 = FCURC(F); + goto err; + } + s = ll_add(&ls_tok, line_no, str->buf); + if (s) + goto err; + + str_prune(str); + break; + case '\"': + F->idx++; + file_fetch_until(F, str, '\"'); + if (FCURC(F) != '\"') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = line_no; + _vos.e_nparm1 = FCURC(F); + goto err; + } + s = ll_add(&ls_tok, line_no, str->buf); + if (s) + goto err; + + str_prune(str); + break; + case '\'': + s = str_append_c(str, FCURC(F)); + if (s) + goto err; + + F->idx++; + if (FCURC(F) == '\\') + F->idx++; + + s = str_append_c(str, FCURC(F)); + if (s) + goto err; + + F->idx++; + if (FCURC(F) != '\'') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = line_no; + _vos.e_nparm1 = FCURC(F); + goto err; + } + + s = str_append_c(str, FCURC(F)); + if (s) + goto err; + + s = ll_add(&ls_tok, line_no, str->buf); + if (s) + goto err; + + str_prune(str); + break; + default: + if (! isalnum(FCURC(F)) && FCURC(F) != '_') { + s = E_PARSER_UNX_CHAR; + _vos.e_nparm0 = line_no; + _vos.e_nparm1 = FCURC(F); + goto err; + } + while (isalnum(FCURC(F)) || FCURC(F) == '_') { + s = str_append_c(str, FCURC(F)); + if (s) + goto err; + F->idx++; + } + s = ll_add(&ls_tok, line_no, str->buf); + if (s) + goto err; + + str_prune(str); + continue; + } + F->idx++; + } + + if (_vos.debug & DBG_PARSER) { + ll_print(ls_tok); + } + + ptok = ls_tok; + s = parsing_token(stmt, &ptok); + if (s) + goto err; + + goto out; +err: + switch (s) { + case E_PARSER_UNK_TOKEN: + case E_PARSER_UNX_TOKEN: + case E_PARSER_UNK_FIELDNAME: + case E_PARSER_INV_FIELDNAME: + case E_PARSER_INV_VALUE: + case E_PARSER_INV_STMT: + case E_PARSER_AMB_FIELDNAME: + _vos.e_nparm0 = ptok->num; + _vos.e_sparm0 = ptok->str; + ptok->str = 0; + break; + case E_PARSER_INV_POS: + _vos.e_nparm0 = ptok->num; + break; + } +out: + if (_vos.debug & DBG_PARSER) { + stmt_print((*stmt)); + } + ll_destroy(&ls_tok); + str_destroy(&str); + file_close(&F); + + return s; +} diff --git a/proc/vos_parser.h b/proc/vos_parser.h new file mode 100644 index 0000000..0ad6c66 --- /dev/null +++ b/proc/vos_parser.h @@ -0,0 +1,10 @@ +#ifndef _VOS_PARSER_H +#define _VOS_PARSER_H 1 + +#include "op/vos_LL.h" +#include "op/vos_File.h" +#include "op/vos_Stmt.h" + +int vos_parsing(struct Stmt **stmt, const char *script); + +#endif diff --git a/proc/vos_set.c b/proc/vos_set.c new file mode 100644 index 0000000..7fc3899 --- /dev/null +++ b/proc/vos_set.c @@ -0,0 +1,33 @@ +#include "proc/vos_set.h" + +int vos_process_set(struct StmtSet *set) +{ + switch (set->var_idx) { + case SET_FILE_BUFFER_SIZE: + _vos.file_buf_size = strtoul(set->value, 0, 0); + if (! _vos.file_buf_size) + _vos.file_buf_size = VOS_DEF_FILE_BUF_SIZE; + break; + + case SET_PROC_CMP_CASE_SENSITIVE: + _vos.proc_cmp_case = CMP_CASE_SENSITIVE; + break; + + case SET_PROC_CMP_CASE_NOTSENSITIVE: + _vos.proc_cmp_case = CMP_CASE_NOTSENSITIVE; + break; + + case SET_PROC_MAX: + _vos.proc_max = strtol(set->value, 0, 0); + if (! _vos.proc_max) + _vos.proc_max = VOS_DEF_PROC_MAX; + break; + + case SET_PROC_MAX_ROW: + _vos.proc_max_row = strtoul(set->value, 0, 0); + if (! _vos.proc_max_row) + _vos.proc_max_row = VOS_DEF_PROC_MAX_ROW; + break; + } + return 0; +} diff --git a/proc/vos_set.h b/proc/vos_set.h new file mode 100644 index 0000000..bf3432f --- /dev/null +++ b/proc/vos_set.h @@ -0,0 +1,9 @@ +#ifndef _VOS_SET_H +#define _VOS_SET_H 1 + +#include "vos.h" +#include "op/vos_StmtSet.h" + +int vos_process_set(struct StmtSet *set); + +#endif diff --git a/proc/vos_sort.c b/proc/vos_sort.c new file mode 100644 index 0000000..627bfd8 --- /dev/null +++ b/proc/vos_sort.c @@ -0,0 +1,396 @@ +#include "proc/vos_sort.h" + +/** + * sort: sort record using mergesort + * @desc: + * about mergesort. the key is in merge. + * merge case 1: + * 1 2 3 + * 4 5 6 + * merge case 2: + * 4 5 6 + * 1 2 3 + * merge case 3: + * 1 3 5 + * 2 4 6 + */ +static struct Record * sort(struct Record *rows, unsigned long n_row) +{ + int s = 0; + unsigned long i = 1; + unsigned long nl = 0; + unsigned long nr = 0; + struct Record *l = 0; + struct Record *r = 0; + struct Record *tmp = 0; + + if (n_row <= 1) { + if (rows) + rows->row_last = rows; + return rows; + } + + nl = n_row / 2; + nr = n_row - nl; + + tmp = rows->row_last; + l = rows; + for (; i < nl; i++) + rows = rows->row_next; + + l->row_last = rows; + r = rows->row_next; + r->row_last = tmp; + l->row_last->row_next = 0; + + if (nl > 1) + l = sort(l, nl); + if (nr > 1) + r = sort(r, nr); + + /* merge case 1 */ + s = record_cmp(l->row_last, r); + if (s <= 0) { + l->row_last->row_next = r; + l->row_last = r->row_last; + r->row_last = 0; + return l; + } + /* merge case 2 : must be '>' not '>=' to keep 'stable' result */ + s = record_cmp(l, r->row_last); + if (s > 0) { + r->row_last->row_next = l; + r->row_last = l->row_last; + l->row_last = 0; + return r; + } + /* merge case 3 */ + rows = 0; + s = record_cmp(l, r); + if (s < 0) { + rows = l; + rows->row_last = rows; + l = l->row_next; + } else if (s == 0) { + rows = l; + l = l->row_next; + rows->row_next = r; + rows->row_last = r; + r = r->row_next; + } else { + rows = r; + rows->row_last = rows; + r = r->row_next; + } + + while (l && r) { + s = record_cmp(l, r); + if (s < 0) { + rows->row_last->row_next = l; + rows->row_last = l; + l = l->row_next; + } else if (s == 0) { + rows->row_last->row_next = l; + l = l->row_next; + rows->row_last->row_next->row_next = r; + rows->row_last = r; + r = r->row_next; + } else { + rows->row_last->row_next = r; + rows->row_last = r; + r = r->row_next; + } + } + + if (l) { + rows->row_last->row_next = l; + while (l->row_next) + l = l->row_next; + rows->row_last = l; + } + if (r) { + rows->row_last->row_next = r; + while (r->row_next) + r = r->row_next; + rows->row_last = r; + } + + return rows; +} + +static int sort_write(struct ProcSort *psort, struct Record *rows) +{ + int s = 0; + char *tmp = 0; + struct File *Fout = 0; + + do { + s = str_raw_randomize(VOS_SORT_TMP_FORMAT, &tmp); + if (s) + return s; + + s = file_open(&Fout, tmp, FOPEN_WO); + if (s == 0) + ll_add(&psort->lsout, psort->tid, tmp); + free(tmp); + } while (s == E_FILE_EXIST); + + s = record_write(rows, Fout, psort->sort->out->fields); + + file_write(Fout); + file_close(&Fout); + + return s; +} + +/** + * @desc: + * for each thread, sort input file from pos_start to pos_end + */ +static void *sort_process(void *parm) +{ + int s = 0; + unsigned long n_row = 0; + struct File *F = 0; + struct Record *R = 0; + struct ProcSort *psort = 0; + struct Record *rows = 0; + + psort = (struct ProcSort *) parm; + + if (_vos.debug & DBG_SORT) { + printf("(%lu) sort pos: %ld to %ld\n", psort->tid, + psort->pos_start, psort->pos_end); + } + + s = file_open(&F, psort->sort->in->filename, FOPEN_RO); + if (s) + goto err; + + F->pos = psort->pos_start; + if (psort->pos_start != 0) { + s = lseek(F->d, psort->pos_start, SEEK_SET); + if (s < 0) { + s = E_FILE_SEEK; + str_raw_copy(F->name, &_vos.e_sparm0); + goto err; + } + + s = file_read(F); + if (s) + goto err; + + /* skip one row */ + s = file_skip_until(F, CH_NEWLINE); + if (s) + goto err; + F->idx++; + } else { + s = file_read(F); + if (s) + goto err; + } + + /* phase 1: create & file rows */ + while (FCURP(F) < psort->pos_end) { + s = record_read(&R, F, psort->sort->in->fields); + if (! R) + break; + + record_add_row(&psort->rows, R); + psort->n_row++; + if (psort->n_row >= _vos.proc_max_row) + break; + } + + /* check if error, but not end of file */ + if (s && s != E_FILE_END) + goto err; + + /* sort rows */ + psort->rows = sort(psort->rows, psort->n_row); + + /* dump rows */ + s = sort_write(psort, psort->rows); + if (s) + goto err; + + if (psort->n_row < _vos.proc_max_row || s == E_FILE_END) + goto out; + + /* phase 2: only use already-created-rows */ + R = psort->rows; + psort->rows = R->row_next; + psort->rows->row_last = R->row_last; + R->row_next = 0; + R->row_last = 0; + n_row = 0; + while (FCURP(F) < psort->pos_end) { + s = record_read2(R, F, psort->sort->in->fields); + if (s) { + if (s == E_FILE_END) + break; + goto err; + } + + record_add_row(&rows, R); + n_row++; + if (n_row >= _vos.proc_max_row) { + rows = sort(rows, n_row); + + s = sort_write(psort, rows); + if (s) + goto err; + + psort->rows = rows; + rows = 0; + n_row = 0; + } + + R = psort->rows; + psort->rows = R->row_next; + if (psort->rows) { + psort->rows->row_last = R->row_last; + R->row_next = 0; + R->row_last = 0; + } + } + + if (n_row) { + if (_vos.debug & DBG_SORT) { + printf(" (%lu) : F->pos %lu, F->idx %lu, "\ + "F->size %lu\n", psort->tid, F->pos, F->idx, + F->size); + printf(" (%lu) : %lu\n", psort->tid, n_row); + printf(" (%lu) : last row : ", psort->tid); + record_print(rows->row_last); + } + + rows = sort(rows, n_row); + + s = sort_write(psort, rows); + if (s) + goto err; + + R->row_next = rows; + psort->rows->row_last->row_next = R; + psort->rows->row_last = rows->row_last; + psort->rows->row_last->row_next = 0; + rows->row_last = 0; + } + + if (_vos.debug & DBG_SORT) { + printf(" (%lu) psort first row : %p\n", psort->tid, psort->rows); + printf(" (%lu) psort last row : %p\n", psort->tid, psort->rows->row_last); + printf(" (%lu) counting rows ...\n", psort->tid); + n_row = 0; + rows = psort->rows; + while (rows->row_next) { + n_row++; + rows = rows->row_next; + } + n_row++; + printf(" (%lu) number of rows : %lu\n", psort->tid, n_row); + printf(" (%lu) last row : %p\n", psort->tid, rows); + } +out: + if (_vos.debug & DBG_SORT) + ll_print(psort->lsout); + s = 0; +err: + file_close(&F); + psort->retval = s; + + return (void *) s; +} + +int vos_process_sort(struct Stmt *sort) +{ + int i = 0; + int s = 0; + unsigned long fsize = 0; + unsigned long esize = 0; + unsigned long all_n_row = 0; + struct ProcSort *sort_proc = 0; + struct LL *lsout = 0; + struct LL *ll = 0; + struct Record *all_rows = 0; + struct Record *cnt_rows = 0; + + s = file_raw_get_size(sort->in->filename, &fsize); + if (s) + goto err; + + esize = fsize / _vos.proc_max; + + sort_proc = (struct ProcSort *) calloc(_vos.proc_max, + sizeof(struct ProcSort)); + if (! sort_proc) { + s = E_MEM; + goto err; + } + + /* create thread for sort */ + for (i = 0; i < _vos.proc_max; i++) { + sort_proc[i].pos_start = i * esize; + + if ((i + 1) == _vos.proc_max) + sort_proc[i].pos_end = fsize; + else + sort_proc[i].pos_end = sort_proc[i].pos_start + esize; + + sort_proc[i].n_row = 0; + sort_proc[i].rows = 0; + sort_proc[i].sort = sort; + + pthread_create(&sort_proc[i].tid, 0, sort_process, + (void *) &sort_proc[i]); + } + + for (i = 0; i < _vos.proc_max; i++) { + pthread_join(sort_proc[i].tid, 0); + + if (sort_proc[i].retval && !s) + s = sort_proc[i].retval; + else { + ll_link(&lsout, sort_proc[i].lsout); + if (! all_rows) + all_rows = sort_proc[i].rows; + else { + all_rows->row_last->row_next = + sort_proc[i].rows; + all_rows->row_last = sort_proc[i].rows->row_last; + } + all_n_row += sort_proc[i].n_row; + } + } + + if (! s) { + if (_vos.debug & DBG_SORT) { + esize = 0; + cnt_rows = all_rows; + printf(" all-rows first row : %p\n", all_rows); + printf(" all-rows last row : %p\n", all_rows->row_last); + while (cnt_rows) { + esize++; + cnt_rows = cnt_rows->row_next; + if (cnt_rows == all_rows->row_last) + printf(" last row found in : %lu\n", esize); + } + printf(" count all rows : %lu\n", esize); + } + /* use already created rows for merge */ + s = vos_sort_merge(sort, lsout, &all_rows, all_n_row); + } +err: + /* remove all temporary file */ + ll = lsout; + while (ll) { + unlink(ll->str); + ll = ll->next; + } + ll_destroy(&lsout); + record_destroy(&all_rows); + free(sort_proc); + return s; +} diff --git a/proc/vos_sort.h b/proc/vos_sort.h new file mode 100644 index 0000000..ca871c9 --- /dev/null +++ b/proc/vos_sort.h @@ -0,0 +1,10 @@ +#ifndef _VOS_SORT_H +#define _VOS_SORT_H 1 + +#include <pthread.h> +#include "type/vos_TProcSort.h" +#include "proc/vos_sort_merge.h" + +int vos_process_sort(struct Stmt *sort); + +#endif diff --git a/proc/vos_sort_merge.c b/proc/vos_sort_merge.c new file mode 100644 index 0000000..30bddf2 --- /dev/null +++ b/proc/vos_sort_merge.c @@ -0,0 +1,241 @@ +#include "proc/vos_sort_merge.h" + +static int mnode_new(struct MNode **node, const int level, const char *file) +{ + int s = 0; + + (*node) = (struct MNode *) calloc(1, sizeof(struct MNode)); + if (! (*node)) + return E_MEM; + + s = file_open(&(*node)->file, file, FOPEN_RO); + if (s) + goto err; + + s = file_read((*node)->file); + if (s) + goto err; + + (*node)->level = level; + s = 0; +err: + if (s && (*node)) { + if ((*node)->file) + file_close(&(*node)->file); + free((*node)); + } + return s; +} + +static void mnode_destroy(struct MNode **node) +{ + if (! (*node)) + return; + if ((*node)->file) + file_close(&(*node)->file); + if ((*node)->row) + record_destroy(&(*node)->row); + mnode_destroy(&(*node)->left); + mnode_destroy(&(*node)->right); + free((*node)); + (*node) = 0; +} + +static void mnode_print(struct MNode *root) +{ + if (root->left) + mnode_print(root->left); + record_print(root->row); + if (root->right) + mnode_print(root->right); +} + +static struct MNode * mnode_insert(struct MNode *root, struct MNode *node) +{ + int s = 0; + + if (! root) + return node; + + s = record_cmp(root->row, node->row); + if (s < 0) { + root->right = mnode_insert(root->right, node); + } else if (s == 0) { + if (root->level < node->level) + root->right = mnode_insert(root->right, node); + else + root->left = mnode_insert(root->left, node); + } else { + root->left = mnode_insert(root->left, node); + } + + return root; +} + +static int merge_init(struct MNode **root, struct LL *lsfile, + struct Field *fld) +{ + int s = 0; + int level = 1; + struct MNode *node = 0; + + while (lsfile) { + s = mnode_new(&node, level, lsfile->str); + if (s) + return s; + + s = record_read(&node->row, node->file, fld); + if (! node->row) + return s; + + (*root) = mnode_insert((*root), node); + + level++; + lsfile = lsfile->next; + } + + return 0; +} + +static struct MNode * mnode_get_loser(struct MNode **root, + struct MNode **loser2) +{ + struct MNode *loser = (*root); + + while (loser->left) { + (*loser2) = loser; + loser = loser->left; + } + + if (loser == (*root)) { + (*root) = (*root)->right; + (*loser2) = (*root); + } else { + (*loser2)->left = loser->right; + } + + if ((*loser2)) { + while ((*loser2)->left) + (*loser2) = (*loser2)->left; + } + + loser->right = 0; + return loser; +} + +int vos_sort_merge(struct Stmt *sort, struct LL *lsfile, + struct Record **_all_rows, unsigned long all_n_row) +{ + int s = 0; + unsigned long n_row = 0; + struct File *F = 0; + struct MNode *root = 0; + struct MNode *loser = 0; + struct MNode *loser2 = 0; + struct Record *rows = 0; + struct Record *R = 0; + struct Record *all_rows = (*_all_rows); + + /* in case of only one file to merge */ + if (! lsfile->next) { + s = rename(lsfile->str, sort->out->filename); + return s; + } + + s = file_open(&F, sort->out->filename, FOPEN_WO); + if (s) + goto err; + + s = merge_init(&root, lsfile, sort->out->fields); + if (s) + goto err; + + R = all_rows; + all_rows = R->row_next; + R->row_next = 0; + R->row_last = 0; + while (root) { + loser2 = 0; + loser = mnode_get_loser(&root, &loser2); + + if (loser2) { + do { + record_add_row(&rows, loser->row); + n_row++; + if (n_row >= all_n_row || ! all_rows) { + s = record_write(rows, F, + sort->out->fields); + if (s) + goto err; + + all_rows = rows; + all_rows->row_last = 0; + rows = 0; + n_row = 0; + } + + loser->row = R; + R = all_rows; + all_rows = R->row_next; + R->row_next = 0; + R->row_last = 0; + + s = record_read2(loser->row, loser->file, + sort->out->fields); + if (s) + break; + + s = record_cmp(loser2->row, loser->row); + } while (s > 0 + || (s == 0 && loser2->level > loser->level)); + } else { + do { + record_add_row(&rows, loser->row); + n_row++; + if (n_row >= all_n_row || ! all_rows) { + s = record_write(rows, F, + sort->out->fields); + if (s) + goto err; + + all_rows = rows; + all_rows->row_last = 0; + rows = 0; + n_row = 0; + } + + loser->row = R; + R = all_rows; + all_rows = R->row_next; + R->row_next = 0; + R->row_last = 0; + + s = record_read2(loser->row, loser->file, + sort->out->fields); + } while (s == 0); + } + if (s == E_FILE_END) + mnode_destroy(&loser); + else + root = mnode_insert(root, loser); + } + + R->row_next = all_rows; + if (n_row) { + s = record_write(rows, F, sort->out->fields); + if (s) + goto err; + + rows->row_last->row_next = R; + (*_all_rows) = rows; + } else { + (*_all_rows) = R; + } + + file_write(F); + s = 0; +err: + mnode_destroy(&root); + file_close(&F); + return s; +} diff --git a/proc/vos_sort_merge.h b/proc/vos_sort_merge.h new file mode 100644 index 0000000..1a0e29e --- /dev/null +++ b/proc/vos_sort_merge.h @@ -0,0 +1,12 @@ +#ifndef _VOS_MERGE_H +#define _VOS_MERGE_H 1 + +#include "type/vos_TMNode.h" +#include "op/vos_StmtSort.h" +#include "op/vos_LL.h" +#include "op/vos_Record.h" + +int vos_sort_merge(struct Stmt *sort, struct LL *lsfile, + struct Record **_all_rows, unsigned long all_n_row); + +#endif diff --git a/type/vos_TBucket.h b/type/vos_TBucket.h new file mode 100644 index 0000000..2ea8d0d --- /dev/null +++ b/type/vos_TBucket.h @@ -0,0 +1,12 @@ +#ifndef _VOS_TYPE_BUCKET_H +#define _VOS_TYPE_BUCKET_H 1 + +#include "type/vos_TRecord.h" + +struct Bucket { + int stat; + struct Record *cnt; + struct Record *p; +}; + +#endif diff --git a/type/vos_TField.h b/type/vos_TField.h new file mode 100644 index 0000000..b39b8c8 --- /dev/null +++ b/type/vos_TField.h @@ -0,0 +1,42 @@ +#ifndef _VOS_TYPE_FIELD_H +#define _VOS_TYPE_FIELD_H 1 + +enum _field_type_idx { + FT_STRING = 0, + FT_NUMBER, + FT_DATETIME, + N_FIELD_TYPE +}; + +enum _fflag_sort_idx { + FFLAG_SORT_ASC = 1, + FFLAG_SORT_DESC = 2, + N_FFLAG_SORT +}; + +enum _fflag_idx { + FFLAG_CREATE = 4, + FFLAG_FILTER = 8, + FFLAG_JOIN = 16, + N_FFLAG +}; + +struct Field { + int idx; + int flag; + int type; + int left_q; + int right_q; + int start_p; + int end_p; + int sep; + int fltr_idx; + int fltr_rule; + int (*fop)(const int, const void *, const void *); + char *name; + char *date_format; + char *fltr_v; + struct Field *next; +}; + +#endif diff --git a/type/vos_TFile.h b/type/vos_TFile.h new file mode 100644 index 0000000..cfadda6 --- /dev/null +++ b/type/vos_TFile.h @@ -0,0 +1,27 @@ +#ifndef _VOS_TYPE_FILE_H +#define _VOS_TYPE_FILE_H 1 + +enum _file_open_flag { + FOPEN_RO = 1, + FOPEN_WO = 2 +}; + +/** + * @desc: + * d - descriptor + * idx - index of buffer + * buf - content of file + * size - size of buf + * pos - pointer to last file position from last read/write. + * to get the current file position: pos + idx + */ +struct File { + int d; + long int idx; + long int size; + unsigned long pos; + const char *name; + char *buf; +}; + +#endif diff --git a/type/vos_TFilter.h b/type/vos_TFilter.h new file mode 100644 index 0000000..618eb0d --- /dev/null +++ b/type/vos_TFilter.h @@ -0,0 +1,22 @@ +#ifndef _VOS_TYPE_FILTER_H +#define _VOS_TYPE_FILTER_H 1 + +enum _filter_op_idx { + OP_EQUAL = 0, /* not case sensitive */ + OP_TRUE_EQUAL, /* case sensitive */ + OP_NOT_EQUAL, + OP_NOT_TRUE_EQUAL, + OP_MORE, + OP_LESS, + OP_MORE_EQUAL, + OP_LESS_EQUAL, + N_FLTR_OP +}; + +enum _filter_rule_idx { + FLTR_REJECT = 0, + FLTR_ACCEPT = 1, + N_FLTR_RULE +}; + +#endif diff --git a/type/vos_TLL.h b/type/vos_TLL.h new file mode 100644 index 0000000..5220d79 --- /dev/null +++ b/type/vos_TLL.h @@ -0,0 +1,11 @@ +#ifndef _VOS_TYPE_LL_H +#define _VOS_TYPE_LL_H 1 + +struct LL { + unsigned long num; + char *str; + struct LL *next; + struct LL *last; +}; + +#endif diff --git a/type/vos_TMNode.h b/type/vos_TMNode.h new file mode 100644 index 0000000..bf46cb2 --- /dev/null +++ b/type/vos_TMNode.h @@ -0,0 +1,15 @@ +#ifndef _VOS_TYPE_MERGE_NODE_H +#define _VOS_TYPE_MERGE_NODE_H 1 + +#include "type/vos_TFile.h" +#include "type/vos_TRecord.h" + +struct MNode { + int level; + struct Record *row; + struct File *file; + struct MNode *left; + struct MNode *right; +}; + +#endif diff --git a/type/vos_TProcCreate.h b/type/vos_TProcCreate.h new file mode 100644 index 0000000..70f9242 --- /dev/null +++ b/type/vos_TProcCreate.h @@ -0,0 +1,23 @@ +#ifndef _VOS_TYPE_PROCESS_CREATE_H +#define _VOS_TYPE_PROCESS_CREATE_H 1 + +#include "type/vos_TStmtMeta.h" +#include "type/vos_TBucket.h" +#include "type/vos_TStmt.h" + +enum _cproc_status { + CPROC_START = 1, + CPROC_BUCKETS_FULL, + CPROC_DONE, + CPROC_END +}; + +struct ProcCreate { + pthread_t tid; + int retval; + int status; + struct StmtMeta *in; + struct Bucket *buckets; +}; + +#endif diff --git a/type/vos_TProcSort.h b/type/vos_TProcSort.h new file mode 100644 index 0000000..1539a62 --- /dev/null +++ b/type/vos_TProcSort.h @@ -0,0 +1,18 @@ +#ifndef _VOS_TYPE_PROCESS_SORT_H +#define _VOS_TYPE_PROCESS_SORT_H 1 + +#include "type/vos_TLL.h" +#include "type/vos_TStmt.h" + +struct ProcSort { + pthread_t tid; + int retval; + unsigned long pos_start; + unsigned long pos_end; + unsigned long n_row; + struct Record *rows; + const struct Stmt *sort; + struct LL *lsout; +}; + +#endif diff --git a/type/vos_TRecord.h b/type/vos_TRecord.h new file mode 100644 index 0000000..1bd0d97 --- /dev/null +++ b/type/vos_TRecord.h @@ -0,0 +1,16 @@ +#ifndef _VOS_TYPE_RECORD_H +#define _VOS_TYPE_RECORD_H 1 + +#include "type/vos_TString.h" + +struct Record { + int idx; + int flag; + struct String *v; + struct Record *fld_next; + struct Record *fld_last; + struct Record *row_next; + struct Record *row_last; +}; + +#endif diff --git a/type/vos_TStmt.h b/type/vos_TStmt.h new file mode 100644 index 0000000..a6e79ef --- /dev/null +++ b/type/vos_TStmt.h @@ -0,0 +1,26 @@ +#ifndef _VOS_TYPE_STMT_H +#define _VOS_TYPE_STMT_H 1 + +#include "type/vos_TStmtSet.h" +#include "type/vos_TStmtMeta.h" + +enum _stmt_type_idx { + STMT_SET = 0, + STMT_LOAD, + STMT_CREATE, + STMT_SORT, + STMT_JOIN, + N_STMT_TYPE +}; + +struct Stmt { + unsigned short type; + struct StmtSet *set; + struct StmtMeta *in; + struct StmtMeta *out; + struct Stmt *next; + struct Stmt *prev; + struct Stmt *last; +}; + +#endif diff --git a/type/vos_TStmtJoin.h b/type/vos_TStmtJoin.h new file mode 100644 index 0000000..aae8fc3 --- /dev/null +++ b/type/vos_TStmtJoin.h @@ -0,0 +1,17 @@ +#ifndef _VOS_TYPE_STMTJOIN_H +#define _VOS_TYPE_STMTJOIN_H 1 + +enum _stmt_join_flag { + JOIN_NORMAL = 0, + JOIN_OUTER = 1, + JOIN_ANTI = 2, + N_JOIN_FLAG +}; + +enum _stmt_join_sort_flag { + JOIN_UNSORTED = 4, + JOIN_SORTED = 8, + N_JOIN_SORT_FLAG +}; + +#endif diff --git a/type/vos_TStmtMeta.h b/type/vos_TStmtMeta.h new file mode 100644 index 0000000..5e37c3b --- /dev/null +++ b/type/vos_TStmtMeta.h @@ -0,0 +1,14 @@ +#ifndef _VOS_TYPE_STMTMETA_H +#define _VOS_TYPE_STMTMETA_H 1 + +#include "type/vos_TField.h" + +struct StmtMeta { + int flag; + char *filename; + char *alias; + struct Field *fields; + struct StmtMeta *next; +}; + +#endif diff --git a/type/vos_TStmtSet.h b/type/vos_TStmtSet.h new file mode 100644 index 0000000..849a370 --- /dev/null +++ b/type/vos_TStmtSet.h @@ -0,0 +1,18 @@ +#ifndef _VOS_TYPE_STMTSET_H +#define _VOS_TYPE_STMTSET_H 1 + +enum _set_idx { + SET_FILE_BUFFER_SIZE = 0, + SET_PROC_CMP_CASE_SENSITIVE, + SET_PROC_CMP_CASE_NOTSENSITIVE, + SET_PROC_MAX, + SET_PROC_MAX_ROW, + N_SET +}; + +struct StmtSet { + unsigned short var_idx; + char *value; +}; + +#endif diff --git a/type/vos_TString.h b/type/vos_TString.h new file mode 100644 index 0000000..ee231fa --- /dev/null +++ b/type/vos_TString.h @@ -0,0 +1,10 @@ +#ifndef _VOS_TYPE_STRING_H +#define _VOS_TYPE_STRING_H 1 + +struct String { + int idx; + int len; + char *buf; +}; + +#endif diff --git a/type/vos_TVos.h b/type/vos_TVos.h new file mode 100644 index 0000000..a22ff65 --- /dev/null +++ b/type/vos_TVos.h @@ -0,0 +1,42 @@ +#ifndef _VOS_T_H +#define _VOS_T_H + +/** + * @desc: + * - DBG_SCRIPT : don't process the script + * use to check if script is valid or not + * - DBG_PARSER : debug parsing process and execute statement in + * the script + * - DBG_SORT : debug sort process + * - DBG_CREATE : debug create process + * - DBG_JOIN : debug join process + * - DBG_ALL : debug all process + */ +enum _vos_debug { + DBG_SCRIPT = 1, + DBG_PARSER = 2, + DBG_SORT = 4, + DBG_CREATE = 8, + DBG_JOIN = 16, + DBG_ALL = 30 +}; + +enum _vos_cmp_case { + CMP_CASE_SENSITIVE = 0, + CMP_CASE_NOTSENSITIVE +}; + +struct Vos { + int debug; /* debug parameter */ + int e_nparm0; /* first error parameter for number */ + int e_nparm1; /* second error parameter for number */ + int proc_cmp_case; /* use compare case sensitive ? */ + unsigned long file_buf_size; /* size of buffer for file */ + unsigned long proc_max; /* maximum process for sort */ + unsigned long proc_max_row; /* maximum row for each process */ + char *script; /* vos script */ + char *e_sparm0; /* first error parameter (string) */ + char *e_sparm1; /* second error parameter (string) */ +}; + +#endif @@ -0,0 +1,156 @@ +#include "proc/vos_parser.h" +#include "proc/vos_set.h" +#include "proc/vos_load.h" +#include "proc/vos_sort.h" +#include "proc/vos_create.h" +#include "proc/vos_join.h" + +/** + * @return: + * < 0..(n-1) : success + * < -1 : fail + */ +int get_token_idx(const char **ls, const unsigned int n, const char *tok) +{ + int i = n - 1; + int s = 0; + + if (! (*ls) || ! tok) + return -1; + + for (; i >= 0; i--) { + s = strcasecmp(ls[i], tok); + if (s == 0) + return i; + } + + return i; +} + +static int vos_init(int argc, char **argv) +{ + /* very lazy parsing argument */ + if (argc < 1 || argc == 2 || argc > 3) + return E_VOS_PARAM; + + _vos.debug = 0; + + if (argc == 3) { + if (argv[1][0] != '-') + return E_VOS_PARAM; + if (argv[1][1] != 'd') + return E_VOS_PARAM; + _vos.debug = strtol(argv[2], 0, 0); + } + + _vos.file_buf_size = VOS_DEF_FILE_BUF_SIZE; + _vos.proc_cmp_case = VOS_DEF_PROC_CMP_CASE; + _vos.proc_max = VOS_DEF_PROC_MAX; + _vos.proc_max_row = VOS_DEF_PROC_MAX_ROW; + _vos.script = argv[argc]; + + srand(time((void *) 0)); + + return 0; +} + +static int vos_process(struct Stmt *stmt) +{ + int s; + + while (stmt) { + switch (stmt->type) { + case STMT_SET: + vos_process_set(stmt->set); + break; + case STMT_LOAD: + s = vos_process_load(stmt); + if (s) + return s; + break; + case STMT_SORT: + s = vos_process_sort(stmt); + if (s) + return s; + break; + case STMT_CREATE: + s = vos_process_create(stmt); + if (s) + return s; + break; + case STMT_JOIN: + s = vos_process_join(stmt); + if (s) + return s; + break; + } + stmt = stmt->next; + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + int s; + struct Stmt *stmt = 0; + + s = vos_init(argc - 1, argv); + if (s) + return s; + + s = vos_parsing(&stmt, _vos.script); + if (s) + goto err; + + if (! (_vos.debug & DBG_SCRIPT)) + s = vos_process(stmt); + + if (! s) + goto out; + +err: + switch (s) { + case E_VOS_PARAM: + case E_FILE_NOT_OPEN: + case E_MEM: + vos_error0(s); + break; + case E_FILE_OPEN: + case E_FILE_EXIST: + case E_FILE_NOT_EXIST: + case E_FILE_SEEK: + case E_FILE_READ: + case E_FILE_WRITE: + vos_error1(s, _vos.e_sparm0); + break; + case E_PARSER_INV_POS: + vos_error1(s, _vos.e_nparm0); + break; + case E_PARSER_UNX_CHAR: + vos_error2(s, _vos.e_nparm0, _vos.e_nparm1); + break; + case E_PARSER_UNX_TOKEN: + case E_PARSER_UNK_TOKEN: + case E_PARSER_UNK_FIELDNAME: + case E_PARSER_INV_FIELDNAME: + case E_PARSER_INV_VALUE: + case E_PARSER_INV_STMT: + case E_PARSER_AMB_FIELDNAME: + vos_error2(s, _vos.e_nparm0, _vos.e_sparm0); + break; + case E_FILE_END: + break; + default: + fprintf(stderr, "vos error number : %d\n", s); + } + + if (_vos.e_sparm0) + free(_vos.e_sparm0); + if (_vos.e_sparm1) + free(_vos.e_sparm1); +out: + stmt_destroy(&stmt); + + return s; +} @@ -0,0 +1,19 @@ +#ifndef _VOS_H +#define _VOS_H 1 + +#include "type/vos_TVos.h" + +#define VOS_DEF_DATE_FORMAT "YYYY/MM/DD" +#define VOS_DEF_FILE_BUF_SIZE 8192 +#define VOS_DEF_PROC_CMP_CASE CMP_CASE_SENSITIVE +#define VOS_DEF_PROC_MAX 2 +#define VOS_DEF_PROC_MAX_ROW 100000 +#define VOS_SORT_OUT_FORMAT "sort.XXXXXXXX" +#define VOS_SORT_TMP_FORMAT "tmp.sort.XXXXXXXX" +#define VOS_JOIN_OUT_FORMAT "join.XXXXXXXX" + +struct Vos _vos; + +int get_token_idx(const char **ls, const unsigned int n, const char *tok); + +#endif diff --git a/vos_errno.c b/vos_errno.c new file mode 100644 index 0000000..5f340e1 --- /dev/null +++ b/vos_errno.c @@ -0,0 +1,27 @@ +#include "vos_errno.h" + +const char *vos_errmsg[N_VOS_ERRNO] = { + "\0", + "Usage: vos [-d {1,2,4,8,16}] <vos script>\n\0", + + "line %d: unexpected character '%c'.\n\0", + "line %d: unexpected token '%s'.\n\0", + "line %d: unknown token '%s'.\n\0", + "line %d: unknown field name '%s'.\n\0", /* 5 */ + "line %d: invalid field name '%s'.\n\0", + "line %d: invalid position value.\n\0", + "line %d: invalid format or value '%s'.\n\0", + "line %d: invalid statement '%s'.\n\0", + "line %d: duplicate/ambigous field name '%s'.\n\0", /* 10 */ + + "error: cannot open file '%s'.\n\0", + "error: file '%s' exist.\n\0", + "error: file '%s' is not exist.\n\0", + "error: file not open\n\0", + "error: cannot seek file '%s'.\n\0", /* 15 */ + "error: cannot read file.\n\0", + "error: errot at writing to file.\n\0", + "error: end of file.\n\0", + "error: converting string to number.\n\0", + "error: out of memory.\n\0" /* 20 */ +}; diff --git a/vos_errno.h b/vos_errno.h new file mode 100644 index 0000000..a3b7c75 --- /dev/null +++ b/vos_errno.h @@ -0,0 +1,37 @@ +#ifndef _VOS_ERRNO_H +#define _VOS_ERRNO_H 1 + +#include <errno.h> + +enum vos_errno { + E_VOS_PARAM = 1, +/* parser module error number */ + E_PARSER_UNX_CHAR, + E_PARSER_UNX_TOKEN, + E_PARSER_UNK_TOKEN, + E_PARSER_UNK_FIELDNAME, + E_PARSER_INV_FIELDNAME, + E_PARSER_INV_POS, + E_PARSER_INV_VALUE, + E_PARSER_INV_STMT, + E_PARSER_AMB_FIELDNAME, /* 10 */ +/* error number from system */ + E_FILE_OPEN, + E_FILE_EXIST, + E_FILE_NOT_EXIST, + E_FILE_NOT_OPEN, + E_FILE_SEEK, /* 15 */ + E_FILE_READ, + E_FILE_WRITE, + E_FILE_END, + E_STRTONUM, + E_MEM, + N_VOS_ERRNO +}; +extern const char *vos_errmsg[N_VOS_ERRNO]; + +#define vos_error0(N) fprintf(stderr,vos_errmsg[N]) +#define vos_error1(N,V) fprintf(stderr,vos_errmsg[N],V) +#define vos_error2(N,V,W) fprintf(stderr,vos_errmsg[N],V,W) + +#endif |
