/** * @author Mislav Čakarić edited by Ljubo Barać * @brief Function for renaming table and/or attribute in table (moved from rename.c) * @param old_table_name old name of the table * @param new_table_name new name of the table * @param old_attr name of the attribute to rename * @param new_attr new name for the attribute to rename * @return EXIT_ERROR or EXIT_SUCCESS */ int AK_rename(char *old_table_name, char *old_attr, char *new_table_name, char *new_attr) { AK_PRO; table_addresses *adresses = (table_addresses *) AK_get_table_addresses(old_table_name); int tab_addresses[MAX_NUM_OF_BLOCKS]; int num_extents = 0, num_blocks = 0; register int i, j; AK_mem_block *mem_block; if (strcmp(old_attr, new_attr) != 0) { //SEARCH FOR ALL BLOCKS IN SEGMENT i = 0; while (adresses->address_from[i]) { for (j = adresses->address_from[i]; j <= adresses->address_to[i]; j++) { tab_addresses[num_blocks] = j; num_blocks++; } num_extents++; i++; } AK_header newHeader[MAX_ATTRIBUTES]; mem_block = (AK_mem_block *) AK_get_block(tab_addresses[0]); memcpy(&newHeader, mem_block->block->header, sizeof (mem_block->block->header)); for (i = 0; i < MAX_ATTRIBUTES; i++) { if (strcmp(newHeader[i].att_name, old_attr) == 0) { Ak_dbg_messg(HIGH, REL_OP, "AK_rename: the attribute names are the same at position %d!\n", i); memset(&newHeader[i].att_name, 0, MAX_ATT_NAME); memcpy(&newHeader[i].att_name, new_attr, strlen(new_attr)); break; } else if (strcmp(newHeader[i].att_name, "\0") == 0) { //if there is no more attributes Ak_dbg_messg(MIDDLE, REL_OP, "AK_rename: ERROR: atribute: %s does not exist in this table\n", old_attr); AK_EPI; return (EXIT_ERROR); } } //replacing old headers with new ones for (i = 0; i < num_blocks; i++) { mem_block = AK_get_block(tab_addresses[i]); memcpy(&mem_block->block->header, newHeader, sizeof (AK_header) * MAX_ATTRIBUTES); AK_mem_block_modify(mem_block, BLOCK_DIRTY); } } if (strcmp(old_table_name, new_table_name) != 0) {//new name is different than old, and old needs to be replaced struct list_node *expr; expr = 0; AK_selection(old_table_name, new_table_name, expr); AK_delete_segment(old_table_name, SEGMENT_TYPE_TABLE); } AK_EPI; return EXIT_SUCCESS; }
/** * @author Matija Novak, updated by Matija Šestak( function now uses caching) * @brief Function to find AK_free space in some block betwen block addresses. It's made for insert_row() * @param address addresses of extents * @return address of the block to write in */ int AK_find_AK_free_space(table_addresses * addresses) { AK_mem_block *mem_block; int from = 0, to = 0, j = 0, i = 0; AK_PRO; Ak_dbg_messg(HIGH, MEMO_MAN, "find_AK_free_space: Searching for block that has AK_free space < 500 \n"); for (j = 0; j < MAX_EXTENTS_IN_SEGMENT; j++) { if (addresses->address_from != 0) { from = addresses->address_from[j]; to = addresses->address_to[j]; //searching block for (i = from; i <= to; i++) { mem_block = AK_get_block(i); int AK_free_space_on = mem_block->block->AK_free_space; Ak_dbg_messg(HIGH, MEMO_MAN, "find_AK_free_space: FREE SPACE %d\n", mem_block->block->AK_free_space); if ((AK_free_space_on < MAX_FREE_SPACE_SIZE) && (mem_block->block->last_tuple_dict_id < MAX_LAST_TUPLE_DICT_SIZE_TO_USE)) //found AK_free block to write { AK_EPI; return i; } } } else break; } //I cant call function from memoman must consider another solution to place these functions int adr = -1; //need to create new extent AK_EPI; return adr; }
/** * @author Mislav Čakarić * @brief Function that inserts a bucket to block * @param indexName name of index * @param data content of bucket stored in char array * @param type type of bucket (MAIN_BUCKET or HASH_BUCKET) * @return address structure with data where the bucket is stored */ struct_add* Ak_insert_bucket_to_block(char *indexName, char *data, int type) { int size, id; AK_PRO; struct_add *add = (struct_add*) AK_malloc(sizeof (struct_add)); add->addBlock = 0; add->indexTd = 0; int adr_to_write = (int) AK_find_AK_free_space(AK_get_index_addresses(indexName)); if (adr_to_write == -1) adr_to_write = (int) AK_init_new_extent(indexName, SEGMENT_TYPE_INDEX); if (adr_to_write == 0){ AK_EPI; return add; } AK_block *block = (AK_block*) AK_read_block(adr_to_write); Ak_dbg_messg(HIGH, INDICES, "insert_bucket_to_block: Position to write (tuple_dict_index) %d\n", adr_to_write); switch (type) { case MAIN_BUCKET: size = sizeof (main_bucket); break; case HASH_BUCKET: size = sizeof (hash_bucket); break; } id = block->last_tuple_dict_id + 1; memcpy(&block->data[block->AK_free_space], data, size); block->tuple_dict[id].address = block->AK_free_space; block->AK_free_space += size; block->tuple_dict[id].type = type; block->tuple_dict[id].size = size; block->last_tuple_dict_id = id; AK_write_block(block); add->addBlock = adr_to_write; add->indexTd = id; AK_EPI; return add; }
/** * @author Dino Laktašić * @brief Function to make union of the two tables. Union is implemented for working with multiple sets of data, i.e. duplicate * tuples can be written in same table (union) * @param srcTable1 name of the first table * @param srcTable2 name of the second table * @param dstTable name of the new table * @return if success returns EXIT_SUCCESS, else returns EXIT_ERROR */ int AK_union(char *srcTable1, char *srcTable2, char *dstTable) { AK_PRO; table_addresses *src_addr1 = (table_addresses*) AK_get_table_addresses(srcTable1); table_addresses *src_addr2 = (table_addresses*) AK_get_table_addresses(srcTable2); int startAddress1 = src_addr1->address_from[0]; int startAddress2 = src_addr2->address_from[0]; if ((startAddress1 != 0) && (startAddress2 != 0)) { register int i, j, k; i = j = k = 0; AK_mem_block *tbl1_temp_block = (AK_mem_block *) AK_get_block(startAddress1); AK_mem_block *tbl2_temp_block = (AK_mem_block *) AK_get_block(startAddress2); int num_att = AK_check_tables_scheme(tbl1_temp_block, tbl2_temp_block, "Union"); int address, type, size; char data[MAX_VARCHAR_LENGTH]; //initialize new segment AK_header *header = (AK_header *) AK_malloc(num_att * sizeof (AK_header)); memcpy(header, tbl1_temp_block->block->header, num_att * sizeof (AK_header)); AK_initialize_new_segment(dstTable, SEGMENT_TYPE_TABLE, header); AK_free(header); //AK_list *row_root = (AK_list *) AK_malloc(sizeof (AK_list)); struct list_node *row_root = (struct list_node *) AK_malloc(sizeof (struct list_node)); //writing first block or table to new segment for (i = 0; src_addr1->address_from[i] != 0; i++) { startAddress1 = src_addr1->address_from[i]; //BLOCK: for each block in table1 extent for (j = startAddress1; j < src_addr1->address_to[i]; j++) { tbl1_temp_block = (AK_mem_block *) AK_get_block(j); //read block from first table //if there is data in the block if (tbl1_temp_block->block->AK_free_space != 0) { for (k = 0; k < DATA_BLOCK_SIZE; k++) { if (tbl1_temp_block->block->tuple_dict[k].type == FREE_INT) break; address = tbl1_temp_block->block->tuple_dict[k].address; size = tbl1_temp_block->block->tuple_dict[k].size; type = tbl1_temp_block->block->tuple_dict[k].type; memset(data, '\0', MAX_VARCHAR_LENGTH); memcpy(data, tbl1_temp_block->block->data + address, size); Ak_Insert_New_Element_For_Update(type, data, dstTable, tbl1_temp_block->block->header[k % num_att].att_name, row_root, 0); if ((k + 1) % num_att == 0 && k != 0) { Ak_insert_row(row_root); Ak_DeleteAll_L3(&row_root); } } } } } //writing first block or table to new segment for (i = 0; src_addr2->address_from[i] != 0; i++) { startAddress2 = src_addr2->address_from[i]; //BLOCK: for each block in table2 extent for (j = startAddress2; j < src_addr2->address_to[i]; j++) { tbl2_temp_block = (AK_mem_block *) AK_get_block(j); //read block from second table //if there is data in the block if (tbl2_temp_block->block->AK_free_space != 0) { for (k = 0; k < DATA_BLOCK_SIZE; k++) { if (tbl2_temp_block->block->tuple_dict[k].type == FREE_INT) break; address = tbl2_temp_block->block->tuple_dict[k].address; size = tbl2_temp_block->block->tuple_dict[k].size; type = tbl2_temp_block->block->tuple_dict[k].type; memset(data, '\0', MAX_VARCHAR_LENGTH); memcpy(data, tbl2_temp_block->block->data + address, size); Ak_Insert_New_Element_For_Update(type, data, dstTable, tbl2_temp_block->block->header[k % num_att].att_name, row_root, 0); if ((k + 1) % num_att == 0) { Ak_insert_row(row_root); Ak_DeleteAll_L3(&row_root); } } } } } AK_free(src_addr1); AK_free(src_addr2); Ak_dbg_messg(LOW, REL_OP, "UNION_TEST_SUCCESS\n\n"); AK_EPI; return EXIT_SUCCESS; } else { Ak_dbg_messg(LOW, REL_OP, "\nAK_union: Table/s doesn't exist!"); AK_free(src_addr1); AK_free(src_addr2); AK_EPI; return EXIT_ERROR; } AK_EPI; }
/** * @author Miroslav Policki * @brief Function for testing file search * @return No return value */ void Ak_filesearch_test() { int i; double f; AK_mem_block *mem_block, tmp; AK_header hBroj_int[4], *hTmp; struct list_node *row_root; AK_PRO; // create table and fill it for testing purposes hTmp = (AK_header *) AK_create_header("Number int", TYPE_INT, FREE_INT, FREE_CHAR, FREE_CHAR); hBroj_int[0] = *hTmp; hTmp = (AK_header *) AK_create_header("Number float", TYPE_FLOAT, FREE_INT, FREE_CHAR, FREE_CHAR); hBroj_int[1] = *hTmp; hTmp = (AK_header *) AK_create_header("Varchar column", TYPE_VARCHAR, FREE_INT, FREE_CHAR, FREE_CHAR); hBroj_int[2] = *hTmp; memset(&hBroj_int[3], 0, sizeof (AK_header)); if (EXIT_ERROR == AK_initialize_new_segment("filesearch test table", SEGMENT_TYPE_TABLE, hBroj_int)) { printf("filesearch_test: ERROR. Unable to create \"filesearch test table \"\n"); AK_EPI; exit(EXIT_ERROR); } row_root = AK_malloc(sizeof (struct list_node)); if (row_root == NULL) { printf("filesearch_test: ERROR. Cannot allocate row_root.\n"); AK_EPI; exit(EXIT_ERROR); } for (i = -10, f = -i; i < 10; i++, f = -i) { Ak_Init_L3(&row_root); Ak_Insert_New_Element(TYPE_INT, &i, "filesearch test table", "Number int", row_root); Ak_Insert_New_Element(TYPE_FLOAT, &f, "filesearch test table", "Number float", row_root); Ak_Insert_New_Element(TYPE_VARCHAR, "test text", "filesearch test table", "Varchar column", row_root); Ak_insert_row(row_root); Ak_DeleteAll_L3(&row_root); } AK_free(row_root); // filesearch usage example starts here { char *szTmp; search_params sp[3]; search_result sr; int iLower, iUpper; double dTmp; sp[0].szAttribute = "Varchar column"; sp[0].iSearchType = SEARCH_ALL; sp[1].szAttribute = "Number int"; sp[1].iSearchType = SEARCH_RANGE; iLower = -5; iUpper = 5; sp[1].pData_lower = &iLower; sp[1].pData_upper = &iUpper; sp[2].szAttribute = "Number float"; sp[2].iSearchType = SEARCH_PARTICULAR; dTmp = 2; sp[2].pData_lower = &dTmp; Ak_dbg_messg(LOW, FILE_MAN, "Calling AK_search_unsorted"); sr = AK_search_unsorted("filesearch test table", sp, 3); for (i = 0; i < sr.iNum_tuple_addresses; i++) { //mem_block = AK_get_block (sr.aiBlocks[i]); // caching should be used when available mem_block = &tmp; mem_block->block = (AK_block *) AK_read_block(sr.aiBlocks[i]); printf("Found:%d\n", *((int *) (mem_block->block->data + mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 0].address))); printf("Found:%f\n", *((double *) (mem_block->block->data + mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 1].address))); szTmp = AK_malloc(mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].size + 1); memcpy(szTmp, mem_block->block->data + mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].address, mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].size); szTmp[mem_block->block->tuple_dict[sr.aiTuple_addresses[i] + 2].size] = '\0'; printf("Found:%s\n", szTmp); AK_free(szTmp); } AK_deallocate_search_result(sr); } AK_EPI; }
/** * @author Dino Laktašić * @brief Function that produces a difference of the two tables. Table addresses are get through names of tables. * Specially start addresses are taken from them. They are used to allocate blocks for them. It is checked whether the tables have same table schemas. If not, it returns EXIT_ERROR. New segment for result of difference operation is initialized. Function compares every block in extent of the first table with every block in extent of second table. If there is a difference between their rows, they are put in dstTable. * @param srcTable1 name of the first table * @param srcTable2 name of the second table * @param dstTable name of the new table * @return if success returns EXIT_SUCCESS, else returns EXIT_ERROR */ int AK_difference(char *srcTable1, char *srcTable2, char *dstTable) { AK_PRO; table_addresses *src_addr1 = (table_addresses*) AK_get_table_addresses(srcTable1); table_addresses *src_addr2 = (table_addresses*) AK_get_table_addresses(srcTable2); int startAddress1 = src_addr1->address_from[0]; int startAddress2 = src_addr2->address_from[0]; if ((startAddress1 != 0) && (startAddress2 != 0)) { register int i, j, k, l, m, n, o; i = j = k = l = 0; AK_mem_block *tbl1_temp_block = (AK_mem_block *) AK_get_block(startAddress1); AK_mem_block *tbl2_temp_block = (AK_mem_block *) AK_get_block(startAddress2); int num_att = AK_check_tables_scheme(tbl1_temp_block, tbl2_temp_block, "Difference"); if (num_att == EXIT_ERROR) { AK_EPI; return EXIT_ERROR; } int address, type, size; int different, num_rows, temp_int,summ; different = num_rows = temp_int = summ = 0; float temp_float = 0; char data1[MAX_VARCHAR_LENGTH]; char data2[MAX_VARCHAR_LENGTH]; //initialize new segment AK_header *header = (AK_header *) AK_malloc(num_att * sizeof (AK_header)); memcpy(header, tbl1_temp_block->block->header, num_att * sizeof (AK_header)); AK_initialize_new_segment(dstTable, SEGMENT_TYPE_TABLE, header); AK_free(header); struct list_node * row_root = (struct list_node *) AK_malloc(sizeof(struct list_node)); for (i = 0; src_addr1->address_from[i] != 0; i++) { startAddress1 = src_addr1->address_from[i]; //BLOCK: for each block in table1 extent for (j = startAddress1; j < src_addr1->address_to[i]; j++) { tbl1_temp_block = (AK_mem_block *) AK_get_block(j); //read block from first table //if there is data in the block if (tbl1_temp_block->block->AK_free_space != 0) { //TABLE2: for each extent in table2 for (k = 0; k < (src_addr2->address_from[k] != 0); k++) { startAddress2 = src_addr2->address_from[k]; if (startAddress2 != 0) { //BLOCK: for each block in table2 extent for (l = startAddress2; l < src_addr2->address_to[k]; l++) { tbl2_temp_block = (AK_mem_block *) AK_get_block(l); //if there is data in the block if (tbl2_temp_block->block->AK_free_space != 0) { //TUPLE_DICTS: for each tuple_dict in the block for (m = 0; m < DATA_BLOCK_SIZE; m += num_att) { if (tbl1_temp_block->block->tuple_dict[m + 1].type == FREE_INT) break; //TUPLE_DICTS: for each tuple_dict in the block for (n = 0; n < DATA_BLOCK_SIZE; n += num_att) { if (tbl2_temp_block->block->tuple_dict[n + 1].type == FREE_INT) break; //for each element in row for (o = 0; o < num_att; o++) { address = tbl1_temp_block->block->tuple_dict[m + o].address; size = tbl1_temp_block->block->tuple_dict[m + o].size; type = tbl1_temp_block->block->tuple_dict[m + o].type; switch (type) { case TYPE_INT: memcpy(&temp_int, &(tbl1_temp_block->block->data[address]), size); sprintf(data1, "%d", temp_int); break; case TYPE_FLOAT: memcpy(&temp_float, &(tbl1_temp_block->block->data[address]), size); sprintf(data1, "%f", temp_float); break; case TYPE_VARCHAR: default: memset(data1, '\0', MAX_VARCHAR_LENGTH); memcpy(data1, &(tbl1_temp_block->block->data[address]), size); } address = tbl2_temp_block->block->tuple_dict[n + o].address; size = tbl2_temp_block->block->tuple_dict[n + o].size; type = tbl2_temp_block->block->tuple_dict[n + o].type; switch (type) { case TYPE_INT: memcpy(&temp_int, &(tbl2_temp_block->block->data[address]), size); sprintf(data2, "%d", temp_int); break; case TYPE_FLOAT: memcpy(&temp_float, &(tbl2_temp_block->block->data[address]), size); sprintf(data2, "%f", temp_float); break; case TYPE_VARCHAR: default: memset(data2, '\0', MAX_VARCHAR_LENGTH); memcpy(data2, &(tbl2_temp_block->block->data[address]), size); } //if they are the same if(strcmp(data1,data2)==0){ different++; } if(different==(num_att-1)) summ=1; } //if same rows are found don't keep searching if(summ==1)break; } //if there is a difference between tuple_dicts if (summ == 0) { Ak_DeleteAll_L3(&row_root); for (o = 0; o < num_att; o++) { address = tbl1_temp_block->block->tuple_dict[m + o].address; size = tbl1_temp_block->block->tuple_dict[m + o].size; type = tbl1_temp_block->block->tuple_dict[m + o].type; memset(data1, '\0', MAX_VARCHAR_LENGTH); memcpy(data1, tbl1_temp_block->block->data + address, size); Ak_Insert_New_Element(type, data1, dstTable, tbl1_temp_block->block->header[o].att_name, row_root); } Ak_insert_row(row_root); } num_rows = different = summ = 0; } } } } else break; } } } } AK_free(src_addr1); AK_free(src_addr2); Ak_DeleteAll_L3(&row_root); AK_free(row_root); Ak_dbg_messg(LOW, REL_OP, "DIFFERENCE_TEST_SUCCESS\n\n"); AK_EPI; return EXIT_SUCCESS; } else { Ak_dbg_messg(LOW, REL_OP, "\nAK_difference: Table/s doesn't exist!"); AK_free(src_addr1); AK_free(src_addr2); AK_EPI; return EXIT_ERROR; } AK_EPI; }
/** * @author Dino Laktašić. * @brief Main function for generating RA expresion according to selection equivalence rules * @param *list_rel_eq RA expresion as the struct list_node * @return optimised RA expresion as the struct list_node */ struct list_node *AK_rel_eq_selection(struct list_node *list_rel_eq) { int step; //, exit_cond[5] = {0}; AK_PRO; //Initialize temporary linked list struct list_node *temp = (struct list_node *) AK_malloc(sizeof (struct list_node)); Ak_Init_L3(&temp); // struct list_node *list_split_sel; struct list_node *tmp, *temp_elem, *temp_elem_prev, *temp_elem_next; struct list_node *list_elem_next, *list_elem = (struct list_node *) Ak_First_L2(list_rel_eq); //Iterate through all the elements of RA linked list while (list_elem != NULL) { switch (list_elem->type) { case TYPE_OPERATOR: Ak_dbg_messg(LOW, REL_EQ, "\nOPERATOR '%c' SELECTED\n", list_elem->data[0]); Ak_dbg_messg(LOW, REL_EQ, "----------------------\n"); temp_elem = (struct list_node *) Ak_End_L2(temp); temp_elem_prev = (struct list_node *) Ak_Previous_L2(temp_elem, temp); list_elem_next = (struct list_node *) Ak_Next_L2(list_elem); switch (list_elem->data[0]) { //Commutativity of Selection and Projection. case RO_PROJECTION: step = -1; if (temp_elem != NULL) { while (temp_elem != NULL) { if (temp_elem->type == TYPE_OPERAND || temp_elem->type == TYPE_CONDITION) { if (temp_elem->type == TYPE_CONDITION) { temp_elem_prev = (struct list_node *) Ak_Previous_L2(temp_elem, temp); if ((AK_rel_eq_can_commute(list_elem_next, temp_elem) == EXIT_FAILURE) && (temp_elem_prev->data[0] == RO_SELECTION) && (temp_elem_prev->type == TYPE_OPERATOR)) { Ak_InsertAtEnd_L3(list_elem->type, list_elem->data, list_elem->size, temp); Ak_InsertAtEnd_L3(list_elem_next->type, list_elem_next->data, list_elem_next->size, temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with condition (%s) in temp list\n", list_elem->data, list_elem_next->data); step++; break; } else if ((AK_rel_eq_can_commute(list_elem_next, temp_elem) == EXIT_SUCCESS) && (temp_elem_prev->data[0] == RO_SELECTION) && (temp_elem_prev->type == TYPE_OPERATOR)) { Ak_InsertBefore_L2(list_elem->type, list_elem->data, list_elem->size, &temp_elem_prev, &temp); Ak_InsertBefore_L2(list_elem_next->type, list_elem_next->data, list_elem_next->size, &temp_elem_prev, &temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with condition (%s) in temp list\n", list_elem->data, list_elem_next->data); step++; break; } } } temp_elem = (struct list_node *) Ak_Previous_L2(temp_elem, temp); } } if (temp_elem == NULL || step != 0) { Ak_InsertAtEnd_L3(list_elem->type, list_elem->data, list_elem->size, temp); Ak_InsertAtEnd_L3(list_elem_next->type, list_elem_next->data, list_elem_next->size, temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with condition (%s) in temp list\n", list_elem->data, list_elem_next->data); } list_elem = list_elem->next; break; //Cascade of Selection and Commutativity of Selection case RO_SELECTION: //Join cascade selection conditions to one if (temp_elem != NULL && temp_elem_prev != NULL && temp_elem->type == TYPE_CONDITION && temp_elem_prev->data[0] == RO_SELECTION && temp_elem_prev->type == TYPE_OPERATOR) { temp_elem->size = temp_elem->size + list_elem_next->size + strlen(" AND") + 1; //edit to (" AND ") //strcat(temp_elem->data, " AND "); //uncomment for infix use strcat(temp_elem->data, " "); //remove for infix strcat(temp_elem->data, list_elem_next->data); strcat(temp_elem->data, " AND"); //comment if using infix format memcpy(temp_elem->data, temp_elem->data, temp_elem->size); Ak_dbg_messg(MIDDLE, REL_EQ, "::selection cascade - condition changed to (%s) in temp list\n", temp_elem->data); } else { Ak_InsertAtEnd_L3(list_elem->type, list_elem->data, list_elem->size, temp); Ak_InsertAtEnd_L3(list_elem_next->type, list_elem_next->data, list_elem_next->size, temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with attributes (%s) in temp list\n", list_elem->data, list_elem_next->data); } /*//Divide selection condition (slower than upper solution but can be useful in certain cases) list_split_sel = AK_rel_eq_split_condition(list_elem_next->data); struct list_node *list_elem_split = (struct list_node *)FirstL(list_split_sel); if (temp_elem != NULL) { tmp = temp_elem; while (list_elem_split != NULL) { step = 0; while (temp_elem != NULL) { if (temp_elem->type == TYPE_CONDITION || (temp_elem->data[0] == RO_SELECTION && temp_elem->type == TYPE_OPERATOR)) { if (temp_elem->type == TYPE_CONDITION && strcmp(list_elem_next->data, temp_elem->data) == 0) { step = 1; } } else if (!step){ InsertAtEndL(list_elem->type , list_elem->data, list_elem->size, temp); InsertAtEndL(list_elem_next->type, list_elem_split->data, list_elem_split->size, temp); break; } temp_elem = (struct list_node *)PreviousL(temp_elem, temp); } list_elem_split = list_elem_split->next; temp_elem = tmp; } } else { while (list_elem_split != NULL) { InsertAtEndL(list_elem->type , list_elem->data, list_elem->size, temp); InsertAtEndL(list_elem_next->type, list_elem_split->data, list_elem_split->size, temp); list_elem_split = list_elem_split->next; } } DeleteAllL(list_split_sel);*/ list_elem = list_elem->next; break; //Commutativity of Selection and set operations (Union, Intersection, and Set difference) case RO_UNION: case RO_INTERSECT: case RO_EXCEPT: step = -1; while (temp_elem != NULL) { if (temp_elem->type == TYPE_OPERAND || temp_elem->type == TYPE_CONDITION) { step++; temp_elem_prev = (struct list_node *) Ak_Previous_L2(temp_elem, temp); if (temp_elem_prev->data[0] == RO_SELECTION && temp_elem_prev->type == TYPE_OPERATOR) { if (step > 1) { tmp = temp_elem; while (tmp->type != TYPE_OPERAND) { tmp = tmp->next; } Ak_InsertAfter_L2(temp_elem->type, temp_elem->data, temp_elem->size, &tmp, &temp); Ak_InsertAfter_L2(temp_elem_prev->type, temp_elem_prev->data, temp_elem_prev->size, &tmp, &temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with attributes (%s) in temp list\n", temp_elem_prev->data, temp_elem->data); } break; } } else { break; } temp_elem = (struct list_node *) Ak_Previous_L2(temp_elem, temp); } Ak_InsertAtEnd_L3(list_elem->type, list_elem->data, list_elem->size, temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted in temp list\n", list_elem->data); break; case RO_NAT_JOIN: Ak_InsertAtEnd_L3(list_elem->type, list_elem->data, list_elem->size, temp); Ak_InsertAtEnd_L3(list_elem_next->type, list_elem_next->data, list_elem_next->size, temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted in temp list\n", list_elem->data); list_elem = list_elem->next; break; //Commutativity of Selection and Theta join (or Cartesian product) case RO_THETA_JOIN: step = -1; while (temp_elem != NULL) { if (temp_elem->type == TYPE_OPERAND || temp_elem->type == TYPE_CONDITION) { step++; temp_elem_prev = (struct list_node *) Ak_Previous_L2(temp_elem, temp); if (temp_elem_prev->data[0] == RO_SELECTION && temp_elem_prev->type == TYPE_OPERATOR) { if (step > 1) { tmp = temp_elem; temp_elem_next = temp_elem->next; char *data1, *data2; char *cond_attr1, *cond_attr2; char op_selected[2]; memcpy(op_selected, temp_elem_prev->data, 2); data1 = AK_rel_eq_commute_with_theta_join(temp_elem->data, temp_elem_next->data); cond_attr1 = AK_rel_eq_cond_attributes(data1); data2 = AK_rel_eq_commute_with_theta_join(temp_elem->data, (temp_elem_next->next)->data); cond_attr2 = AK_rel_eq_cond_attributes(data2); //Debug lines - can be removed later //printf("CONDITION DATA : data: (%s),(%s), cond: (%s),(%s)\n", data1, data2, cond_attr1, cond_attr2); //printf("SHARE ATTRIBUTE: (%i)\n", AK_rel_eq_share_attributes(cond_attr1, cond_attr2)); if (AK_rel_eq_share_attributes(cond_attr1, cond_attr2)) { if (cond_attr1 != NULL) { //memset(temp_elem->data, '\0', MAX_VARCHAR_LENGHT); temp_elem->size = strlen(data1) + 1; memcpy(temp_elem->data, data1, temp_elem->size); memset(temp_elem->data + temp_elem->size, '\0', MAX_VARCHAR_LENGTH - temp_elem->size); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with attributes (%s) in temp list\n", temp_elem_prev->data, temp_elem->data); } else { struct list_node *temp_elem_prevprev = (struct list_node *) Ak_Previous_L2(temp_elem_prev, temp); temp_elem_prevprev->next = temp_elem; AK_free(temp_elem_prev); struct list_node *temp_elem_prev = temp_elem_prevprev; temp_elem_prev->next = temp_elem_next; AK_free(temp_elem); struct list_node *temp_elem = temp_elem_next; temp_elem_next = temp_elem->next; tmp = temp_elem; } while (tmp->type != TYPE_OPERAND) { tmp = tmp->next; } if (cond_attr2 != NULL) { memset(data2 + strlen(data2), '\0', 1); Ak_InsertAfter_L2(temp_elem->type, data2, strlen(data2) + 1, &tmp, &temp); Ak_InsertAfter_L2(TYPE_OPERATOR, op_selected, 2, &tmp, &temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with attributes (%s) in temp list\n", op_selected, data2); } } AK_free(data1); AK_free(data2); AK_free(cond_attr1); AK_free(cond_attr2); break; } } } else { break; } temp_elem = (struct list_node *) Ak_Previous_L2(temp_elem, temp); } Ak_InsertAtEnd_L3(list_elem->type, list_elem->data, list_elem->size, temp); Ak_InsertAtEnd_L3(list_elem_next->type, list_elem_next->data, list_elem_next->size, temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted with condition (%s) in temp list\n", list_elem->data, list_elem_next->data); list_elem = list_elem->next; break; case RO_RENAME: Ak_InsertAtEnd_L3(list_elem->type, list_elem->data, list_elem->size, temp); Ak_dbg_messg(MIDDLE, REL_EQ, "::operator %s inserted in temp list\n", list_elem->data); break; default: Ak_dbg_messg(LOW, REL_EQ, "Invalid operator: %s", list_elem->data); break; } break; //additional type definition included to distinguish beetween table name and attribute/s case TYPE_ATTRIBS: //printf("::attribute '%s' inserted in the temp list\n", list_elem->data); break; //additional type definition included to distinguish beetween attribute/s and condition case TYPE_CONDITION: //printf("::condition '%s' inserted in the temp list\n", list_elem->data); break; case TYPE_OPERAND: Ak_dbg_messg(MIDDLE, REL_EQ, "::table_name (%s) inserted in the temp list\n", list_elem->data); Ak_InsertAtEnd_L3(TYPE_OPERAND, list_elem->data, list_elem->size, temp); break; default: Ak_dbg_messg(LOW, REL_EQ, "Invalid type: %s", list_elem->data); break; } list_elem = list_elem->next; } //====================================> IMPROVMENTS <======================================= //Recursive RA optimization (need to implement exit condition in place of each operator, ...) //If there is no new changes on the list return generated struct list_nodes //int iter_cond; //for (iter_cond = 0; iter_cond < sizeof(exit_cond); iter_cond++) { // if (exit_cond[iter_cond] == 0) { //// Edit function to return collection of the struct list_nodes //// Generate next RA expr. (new plan) //// temp += remain from the list_rel_eq // AK_rel_eq_selection(temp); // } //} Ak_DeleteAll_L3(&list_rel_eq); AK_EPI; return temp; }
/** * @author Dino Laktašić. * @brief Check if some set of attributes is subset of larger set * <ol> * <li>Tokenize set and subset of projection attributes and store each of them to it's own array</li> * <li>Check if the size of subset array is larger than the size of set array</li> * <li>if the subset array is larger return 0</li> * <li>else sort both arrays ascending</li> * <li>Compare the subset and set items at the same positions, starting from 0</li> * <li>if there is an item in the subset array that doesn't match attribute at the same position in the set array return 0</li> * <li>else continue comparing until final item in the subset array is ritched</li> * <li>on loop exit return EXIT_SUCCESS</li> * </ol> * @param *set set array * @param *subset subset array * @return EXIT_SUCCESS if some set of attributes is subset of larger set, else returns EXIT_FAILURE */ int AK_rel_eq_is_attr_subset(char *set, char *subset) { int len_set, len_subset; int set_id = 0; int subset_id = 0; char *temp_set, *temp_subset; char *token_set, *token_subset; char *save_token_set, *save_token_subset; char *tokens_set[MAX_TOKENS] = {NULL}; char *tokens_subset[MAX_TOKENS] = {NULL}; AK_PRO; if (set == NULL || subset == NULL) { AK_EPI; return EXIT_FAILURE; } len_set = len_subset = 0; temp_set = (char *) AK_calloc(strlen(set), sizeof (char)); temp_subset = (char *) AK_calloc(strlen(subset), sizeof (char)); memcpy(temp_set, set, strlen(set)); memcpy(temp_subset, subset, strlen(subset)); Ak_dbg_messg(HIGH, REL_EQ, "RULE - is (%s) subset of set (%s) in rel_eq_selection\n", subset, set); for ((token_set = strtok_r(temp_set, ATTR_DELIMITER, &save_token_set)); token_set; (token_set = strtok_r(NULL, ATTR_DELIMITER, &save_token_set)), set_id++) { if (set_id < MAX_TOKENS - 1) { tokens_set[set_id] = token_set; len_set++; } } for ((token_subset = strtok_r(temp_subset, ATTR_DELIMITER, &save_token_subset)); token_subset; (token_subset = strtok_r(NULL, ATTR_DELIMITER, &save_token_subset)), subset_id++) { if (subset_id < MAX_TOKENS - 1) { tokens_subset[subset_id] = token_subset; len_subset++; } } if (len_set < len_subset) { Ak_dbg_messg(HIGH, REL_EQ, "RULE - failed (%s) isn't subset of set (%s)!\n", subset, set); AK_EPI; return EXIT_FAILURE; } qsort(tokens_set, len_set, sizeof (char *), AK_strcmp); qsort(tokens_subset, len_subset, sizeof (char *), AK_strcmp); len_set = 0; for (subset_id = 0; tokens_subset[subset_id] != NULL; subset_id++) { for (set_id = 0; tokens_set[set_id] != NULL; set_id++) { if (strcmp(tokens_set[set_id], tokens_subset[subset_id]) == 0) { len_set++; } } } if (len_set != len_subset) { Ak_dbg_messg(HIGH, REL_EQ, "RULE - failed (%s) isn't subset of set (%s)!\n", subset, set); AK_EPI; return EXIT_FAILURE; } AK_free(temp_set); AK_free(temp_subset); Ak_dbg_messg(HIGH, REL_EQ, "RULE - succeed (%s) is subset of set (%s).\n", subset, set); AK_EPI; return EXIT_SUCCESS; }
/** * @author Nikola Bakoš, updated by Matija Šestak (function now uses caching), updated by Mislav Čakarić, updated by Dino Laktašić * @brief Function that extends the segment * @param table_name name of segment to extent * @param extent_type type of extent (can be one of: SEGMENT_TYPE_SYSTEM_TABLE, SEGMENT_TYPE_TABLE, SEGMENT_TYPE_INDEX, SEGMENT_TYPE_TRANSACTION, SEGMENT_TYPE_TEMP * @return address of new extent, otherwise EXIT_ERROR */ int AK_init_new_extent(char *table_name, int extent_type) { char *sys_table; int old_size = 0; int new_size = 0; table_addresses *addresses = (table_addresses *) AK_get_segment_addresses(table_name); int block_address = addresses->address_from[0]; //before 1 int block_written; AK_mem_block *mem_block = AK_get_block(block_address); int start_address = 0; float RESIZE_FACTOR = 0; int end_address; struct list_node *row_root; int obj_id = 0; //!!! to correct header BUG iterate through header from 0 to N-th block while there is //header attributes. Than create header and pass it to function for extent creation below. //Current implementation works only with tables with max MAX_ATTRIBUTES. int i = 0; AK_PRO; for (i = 0; i < MAX_EXTENTS_IN_SEGMENT; i++) { if (addresses->address_from[i] == 0) break; new_size = addresses->address_to[i] - addresses->address_from[i]; if (new_size > old_size) //find largest extent old_size = new_size; } old_size++; if ((start_address = AK_new_extent(1, old_size, extent_type, mem_block->block->header)) == EXIT_ERROR) { printf("AK_init_new_extent: Could not allocate the new extent\n"); AK_EPI; return EXIT_ERROR; } Ak_dbg_messg(HIGH, MEMO_MAN, "AK_init_new_extent: start_address=%i, old_size=%i, extent_type=%i\n", start_address, old_size, extent_type); switch (extent_type) { case SEGMENT_TYPE_TABLE: RESIZE_FACTOR = EXTENT_GROWTH_TABLE; sys_table = "AK_relation"; break; case SEGMENT_TYPE_INDEX: RESIZE_FACTOR = EXTENT_GROWTH_INDEX; sys_table = "AK_index"; break; case SEGMENT_TYPE_TRANSACTION: RESIZE_FACTOR = EXTENT_GROWTH_TRANSACTION; printf("Not implemented yet!\n"); break; case SEGMENT_TYPE_TEMP: RESIZE_FACTOR = EXTENT_GROWTH_TEMP; printf("Not implemented yet!\n"); break; } end_address = start_address + (old_size + old_size * RESIZE_FACTOR); //mem_block = (AK_mem_block *) AK_get_block(0); row_root = (struct list_node *) AK_malloc(sizeof (struct list_node)); Ak_Init_L3(&row_root); //DeleteAllElements(row_root); Ak_Insert_New_Element(TYPE_INT, &obj_id, sys_table, "obj_id", row_root); Ak_Insert_New_Element(TYPE_VARCHAR, table_name, sys_table, "name", row_root); Ak_Insert_New_Element(TYPE_INT, &start_address, sys_table, "start_address", row_root); Ak_Insert_New_Element(TYPE_INT, &end_address, sys_table, "end_address", row_root); Ak_insert_row(row_root); AK_EPI; return start_address; }
/** * @author Matija Novak, updated by Matija Šestak(function now uses caching), modified and renamed by Mislav Čakarić * @brief Function for geting addresses of some table * @param table table name that you search for * @return structure table_addresses witch contains start and end adresses of table extents, when form and to are 0 you are on the end of addresses */ table_addresses *AK_get_segment_addresses(char * segmentName) { int i = 0; int AK_freeVar = 0; int data_adr = 0; int data_size = 0; int data_type = 0; int address_sys; char name_sys[MAX_ATT_NAME]; char *sys_table; sys_table = "AK_relation"; AK_PRO; Ak_dbg_messg(HIGH, MEMO_MAN,"get_segment_addresses: Serching for %s table \n", sys_table); AK_mem_block *mem_block = AK_get_block(0); for (i = 0; i < DATA_BLOCK_SIZE; i++) { memset(name_sys, 0, MAX_ATT_NAME); if (mem_block->block->tuple_dict[i].address == FREE_INT) { break; } data_adr = mem_block->block->tuple_dict[i].address; data_size = mem_block->block->tuple_dict[i].size; data_type = mem_block->block->tuple_dict[i].type; memcpy(name_sys, mem_block->block->data + data_adr, data_size); i++; data_adr = mem_block->block->tuple_dict[i].address; data_size = mem_block->block->tuple_dict[i].size; data_type = mem_block->block->tuple_dict[i].type; memcpy(&address_sys, mem_block->block->data + data_adr, sizeof(int)); if (strcmp(name_sys, sys_table) == 0) { Ak_dbg_messg(HIGH, MEMO_MAN, "get_segment_addresses: Found the address of the %s table: %d \n", sys_table, address_sys); break; } } mem_block = AK_get_block(address_sys); table_addresses * addresses = (table_addresses *) AK_malloc(sizeof (table_addresses)); //memset(addresses->address_from, 0, MAX_EXTENTS_IN_SEGMENT); //memset(addresses->address_to, 0, MAX_EXTENTS_IN_SEGMENT); for (AK_freeVar = 0; AK_freeVar < MAX_EXTENTS_IN_SEGMENT; AK_freeVar++) { addresses->address_from[AK_freeVar] = 0; addresses->address_to[AK_freeVar] = 0; } char name[MAX_VARCHAR_LENGTH]; int address_from; int address_to; int j = 0; for (i = 0; i < DATA_BLOCK_SIZE; i++) { if (mem_block->block->tuple_dict[i].type == FREE_INT) break; if ( (mem_block->block->last_tuple_dict_id) <= i ) break; i++; memcpy(name, &(mem_block->block->data[mem_block->block->tuple_dict[i].address]), mem_block->block->tuple_dict[i].size); name[ mem_block->block->tuple_dict[i].size] = '\0'; i++; memcpy(&address_from, &(mem_block->block->data[mem_block->block->tuple_dict[i].address]), mem_block->block->tuple_dict[i].size); i++; memcpy(&address_to, &(mem_block->block->data[mem_block->block->tuple_dict[i].address]), mem_block->block->tuple_dict[i].size); //if found the table that addresses we need if (strcmp(name, segmentName) == 0) { addresses->address_from[j] = address_from; addresses->address_to[j] = address_to; j++; Ak_dbg_messg(HIGH, MEMO_MAN, "get_segment_addresses(%s): Found addresses of searching segment: %d , %d \n", name, address_from, address_to); } /*if (segmentType == SEGMENT_TYPE_INDEX) { i += 2; }*/ } AK_EPI; return addresses; }
/** * @author Matija Novak * @brief Function initializes the global query memory (variable query_mem) * @return EXIT_SUCCESS if the query memory has been initialized, EXIT_ERROR otherwise */ int AK_query_mem_AK_malloc() { AK_PRO; Ak_dbg_messg(HIGH, MEMO_MAN, "AK_query_mem_AK_malloc: Start query_mem_AK_malloc\n"); /// allocate memory for global variable query_mem if ((query_mem = (AK_query_mem *) AK_malloc(sizeof ( AK_query_mem))) == NULL) { printf("AK_query_mem_AK_malloc: ERROR. Cannot allocate query memory \n"); AK_EPI; exit(EXIT_ERROR); } /// allocate memory for variable query_mem_lib which is used in query_mem->parsed AK_query_mem_lib * query_mem_lib; if ((query_mem_lib = (AK_query_mem_lib *) AK_malloc(sizeof (AK_query_mem_lib))) == NULL) { printf("AK_query_mem_AK_malloc: ERROR. Cannot allocate query library memory \n"); AK_EPI; exit(EXIT_ERROR); } /// allocate memory for variable query_mem_dict which is used in query_mem->dictionary AK_query_mem_dict * query_mem_dict; if ((query_mem_dict = (AK_query_mem_dict *) AK_malloc(sizeof (AK_query_mem_dict))) == NULL) { printf("AK_query_mem_AK_malloc: ERROR. Cannot allocate query dictionary memory \n"); AK_EPI; exit(EXIT_ERROR); } /// allocate memory for variable query_mem_result which is used in query_mem->result AK_query_mem_result * query_mem_result; if ((query_mem_result = (AK_query_mem_result *) AK_malloc(sizeof (AK_query_mem_result))) == NULL) { printf(" AK_query_mem_AK_malloc: ERROR. Cannot allocate query result memory \n"); AK_EPI; exit(EXIT_ERROR); } query_mem_result->results=AK_malloc(MAX_QUERY_RESULT_MEMORY*sizeof(*query_mem_result->results)); /// allocate memory for variable tuple_dict which is used in query_mem->dictionary->dictionary[] AK_tuple_dict * tuple_dict = (AK_tuple_dict *) AK_malloc(sizeof (AK_tuple_dict)); if ((tuple_dict = (AK_tuple_dict *) AK_malloc(sizeof (AK_tuple_dict))) == NULL) { printf(" AK_query_mem_AK_malloc: ERROR. Cannot allocate tuple dictionary memory \n"); AK_EPI; exit(EXIT_ERROR); } memcpy(query_mem_dict->dictionary, tuple_dict, sizeof (* tuple_dict)); query_mem->parsed = query_mem_lib; query_mem->dictionary = query_mem_dict; query_mem->result = query_mem_result; //initializing values for result block status //by default all blocks are free int i=0; for(i=0; i<MAX_QUERY_RESULT_MEMORY; i++){ query_mem->result->results[i].free=1; } /* wrong way because we don't have data only adress which must be written in query_mem variables memcpy(query_mem->parsed, query_mem_lib, sizeof(* query_mem_lib)); memcpy(query_mem->dictionary,query_mem_dict,sizeof(* query_mem_dict)); memcpy(query_mem->result,query_mem_result,sizeof(* query_mem_result));*/ Ak_dbg_messg(HIGH, MEMO_MAN, "AK_query_mem_AK_malloc: Success!\n"); AK_EPI; return EXIT_SUCCESS; }
//int AK_selection(char *srcTable, char *dstTable, AK_list *expr) { int AK_selection(char *srcTable, char *dstTable, struct list_node *expr) { AK_PRO; AK_header *t_header = (AK_header *) AK_get_header(srcTable); int num_attr = AK_num_attr(srcTable); int startAddress = AK_initialize_new_segment(dstTable, SEGMENT_TYPE_TABLE, t_header); if (startAddress == EXIT_ERROR) { AK_EPI; return EXIT_ERROR; } Ak_dbg_messg(LOW, REL_OP, "\nTABLE %s CREATED from %s!\n", dstTable, srcTable); table_addresses *src_addr = (table_addresses*) AK_get_table_addresses(srcTable); /* AK_list_elem row_root = (AK_list_elem) AK_malloc(sizeof (AK_list)); Ak_Init_L3(&row_root); */ struct list_node * row_root = (struct list_node *) AK_malloc(sizeof(struct list_node)); Ak_Init_L3(&row_root); int i, j, k, l, type, size, address; char data[MAX_VARCHAR_LENGTH]; for (i = 0; src_addr->address_from[i] != 0; i++) { for (j = src_addr->address_from[i]; j < src_addr->address_to[i]; j++) { AK_mem_block *temp = (AK_mem_block *) AK_get_block(j); if (temp->block->last_tuple_dict_id == 0) break; for (k = 0; k < DATA_BLOCK_SIZE; k += num_attr) { if (temp->block->tuple_dict[k].type == FREE_INT) break; for (l = 0; l < num_attr; l++) { type = temp->block->tuple_dict[k + l].type; size = temp->block->tuple_dict[k + l].size; address = temp->block->tuple_dict[k + l].address; memcpy(data, &(temp->block->data[address]), size); data[size] = '\0'; Ak_Insert_New_Element(type, data, dstTable, t_header[l].att_name, row_root); } if (AK_check_if_row_satisfies_expression(row_root, expr)) Ak_insert_row(row_root); Ak_DeleteAll_L3(&row_root); } } } AK_free(src_addr); AK_free(t_header); AK_free(row_root); AK_print_table(dstTable); Ak_dbg_messg(LOW, REL_OP, "SELECTION_TEST_SUCCESS\n\n"); AK_EPI; return EXIT_SUCCESS; }