/* * cursor_first_tuple () - * * arguments: * return: NO_CURSOR_SUCCESS, DB_CURSOR_END, error_code * cursor_id(in/out): Cursor Identifier * Note: Makes the first tuple in the LIST FILE referred by the cursor * identifier the current active tuple of the cursor and returns * DB_CURSOR_SUCCESS. If there are no tuples in the list file, * end_of_scan condition is reached. * * Note: if end_of_scan: DB_CURSOR_END, otherwise an error code is returned. */ int cursor_first_tuple (CURSOR_ID * cursor_id_p) { if (VPID_ISNULL (&(cursor_id_p->list_id.first_vpid))) { return DB_CURSOR_END; } if (cursor_fetch_page_having_tuple (cursor_id_p, &cursor_id_p->list_id.first_vpid, FIRST_TPL, 0) != NO_ERROR) { return DB_CURSOR_ERROR; } QFILE_COPY_VPID (&cursor_id_p->current_vpid, &cursor_id_p->list_id.first_vpid); cursor_id_p->position = C_ON; cursor_id_p->tuple_no = 0; if (cursor_id_p->buffer_tuple_count == 0) { cursor_id_p->position = C_AFTER; cursor_id_p->tuple_no = cursor_id_p->list_id.tuple_cnt; return DB_CURSOR_END; } return DB_CURSOR_SUCCESS; }
/* * overflow_traverse () - * return: ovf_vpid on success or NULL on failure * ovf_vfid(in): File where the overflow data is stored * WARNING: MUST BE THE SAME AS IT WAS GIVEN DURING INSERT * ovf_vpid(in): Overflow address * func(in): Overflow address */ static const VPID * overflow_traverse (THREAD_ENTRY * thread_p, const VFID * ovf_vfid, const VPID * ovf_vpid, OVERFLOW_DO_FUNC func) { VPID next_vpid; VPID vpid; PAGE_PTR pgptr = NULL; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ next_vpid = *ovf_vpid; while (!(VPID_ISNULL (&next_vpid))) { pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { goto exit_on_error; } vpid = next_vpid; overflow_next_vpid (ovf_vpid, &next_vpid, pgptr); switch (func) { case OVERFLOW_DO_DELETE: if (ovf_vfid == NULL) /* assert */ { goto exit_on_error; } if (overflow_delete_internal (thread_p, ovf_vfid, &vpid, pgptr) != NO_ERROR) { goto exit_on_error; } break; case OVERFLOW_DO_FLUSH: if (overflow_flush_internal (thread_p, pgptr) != NO_ERROR) { goto exit_on_error; } break; default: break; } } return ovf_vpid; exit_on_error: /* TODO: suspect pgbuf_unfix */ return NULL; }
/* * cursor_last_tuple () - * return: NO_CURSOR_SUCCESS, DB_CURSOR_END, error_code * cursor_id(in/out): Cursor Identifier * Note: Makes the last tuple in the LIST FILE referred by the cursor * identifier the current active tuple of the cursor and returns * DB_CURSOR_SUCCESS. If there are no tuples in the list file, * end_of_scan condition is reached. * * Note: if end_of_scan: DB_CURSOR_END, otherwise an error code is returned. */ int cursor_last_tuple (CURSOR_ID * cursor_id_p) { if (VPID_ISNULL (&(cursor_id_p->list_id.first_vpid))) { return DB_CURSOR_END; } if (cursor_fetch_page_having_tuple (cursor_id_p, &cursor_id_p->list_id.last_vpid, LAST_TPL, 0) != NO_ERROR) { return DB_CURSOR_ERROR; } QFILE_COPY_VPID (&cursor_id_p->current_vpid, &cursor_id_p->list_id.last_vpid); cursor_id_p->position = C_ON; cursor_id_p->tuple_no = cursor_id_p->list_id.tuple_cnt - 1; return DB_CURSOR_SUCCESS; }
/* * overflow_get_nbytes () - GET A PORTION OF THE CONTENT OF AN OVERFLOW RECORD * return: scan status * ovf_vpid(in): Overflow address * recdes(in): Record descriptor * start_offset(in): Start offset of portion to copy * max_nbytes(in): Maximum number of bytes to retrieve * remaining_length(in): The number of remaining bytes to read * * Note: A portion of the content of the overflow record associated with the * given overflow address(ovf_pid) is placed into the area pointed to by * the record descriptor. If the content of the object does not fit in * such an area (i.e., recdes->area_size), an error is returned and a * hint of the number of bytes needed is returned as a negative value in * recdes->length. The length of the retrieved number of bytes is *set * in the the record descriptor (i.e., recdes->length). */ SCAN_CODE overflow_get_nbytes (THREAD_ENTRY * thread_p, const VPID * ovf_vpid, RECDES * recdes, int start_offset, int max_nbytes, int *remaining_length) { OVERFLOW_FIRST_PART *first_part; OVERFLOW_REST_PART *rest_parts; PAGE_PTR pgptr = NULL; char *copyfrom; VPID next_vpid; int copy_length; char *data; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ next_vpid = *ovf_vpid; pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { return S_ERROR; } first_part = (OVERFLOW_FIRST_PART *) pgptr; *remaining_length = first_part->length; if (max_nbytes < 0) { /* The rest of the overflow record starting at start_offset */ max_nbytes = *remaining_length - start_offset; } else { /* Don't give more than what we have */ if (max_nbytes > (*remaining_length - start_offset)) { max_nbytes = *remaining_length - start_offset; } } if (max_nbytes < 0) { /* Likely the offset was beyond the size of the overflow record */ max_nbytes = 0; *remaining_length = 0; } else { *remaining_length -= max_nbytes; } /* Make sure that there is enough space to copy the desired length object */ if (max_nbytes > recdes->area_size) { pgbuf_unfix_and_init (thread_p, pgptr); /* Give a hint to the user of the needed length. Hint is given as a negative value */ recdes->length = -max_nbytes; return S_DOESNT_FIT; } else if (max_nbytes == 0) { pgbuf_unfix_and_init (thread_p, pgptr); recdes->length = 0; return S_SUCCESS; } recdes->length = max_nbytes; /* Start copying the object */ data = recdes->data; copyfrom = (char *) first_part->data; next_vpid = first_part->next_vpid; while (max_nbytes > 0) { /* Continue seeking until the starting offset is reached (passed) */ if (start_offset > 0) { /* Advance .. seek as much as you can */ copy_length = (int) ((copyfrom + start_offset) > ((char *) pgptr + DB_PAGESIZE) ? DB_PAGESIZE - (copyfrom - (char *) pgptr) : start_offset); start_offset -= copy_length; copyfrom += copy_length; } /* * Copy as much as you can when you do not need to continue seeking, * and there is something to copy in current page (i.e., not at end * of the page) and we are not located at the end of the overflow record. */ if (start_offset == 0) { if (copyfrom + max_nbytes > (char *) pgptr + DB_PAGESIZE) { copy_length = DB_PAGESIZE - CAST_BUFLEN (copyfrom - (char *) pgptr); } else { copy_length = max_nbytes; } /* If we were not at the end of the page, perform the copy */ if (copy_length > 0) { memcpy (data, copyfrom, copy_length); data += copy_length; max_nbytes -= copy_length; } } pgbuf_unfix_and_init (thread_p, pgptr); if (max_nbytes > 0) { if (VPID_ISNULL (&next_vpid)) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_HEAP_OVFADDRESS_CORRUPTED, 3, ovf_vpid->volid, ovf_vpid->pageid, NULL_SLOTID); return S_ERROR; } pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { recdes->length = 0; return S_ERROR; } rest_parts = (OVERFLOW_REST_PART *) pgptr; copyfrom = (char *) rest_parts->data; next_vpid = rest_parts->next_vpid; } } return S_SUCCESS; }
/* * overflow_update () - Update the content of a multipage data * return: ovf_vpid on success or NULL on failure * ovf_vfid(in): File where the overflow data is stored * WARNING: MUST BE THE SAME AS IT WAS GIVEN DURING INSERT * ovf_vpid(in): Overflow address * recdes(in): Record descriptor * * Note: The function may allocate or deallocate several overflow pages if * the multipage data increase/decrease in length. * * Overflow pages are not locked in any mode since they are not shared * by other data and its address is know by accessing the relocation * overflow record which has been appropriately locked. */ const VPID * overflow_update (THREAD_ENTRY * thread_p, const VFID * ovf_vfid, const VPID * ovf_vpid, RECDES * recdes) { OVERFLOW_FIRST_PART *first_part = NULL; OVERFLOW_REST_PART *rest_parts = NULL; char *copyto; OVERFLOW_RECV_LINKS recv; VPID tmp_vpid; int hdr_length; int copy_length; int old_length = 0; int length; char *data; VPID next_vpid; VPID *addr_vpid_ptr; LOG_DATA_ADDR addr; LOG_DATA_ADDR logical_undoaddr; bool isnewpage = false; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ addr.vfid = ovf_vfid; addr.offset = 0; logical_undoaddr.vfid = ovf_vfid; logical_undoaddr.offset = 0; logical_undoaddr.pgptr = NULL; recv.ovf_vfid = *ovf_vfid; next_vpid = *ovf_vpid; data = recdes->data; length = recdes->length; while (length > 0) { addr.pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH); if (addr.pgptr == NULL) { goto exit_on_error; } addr_vpid_ptr = pgbuf_get_vpid_ptr (addr.pgptr); /* Log before and after images */ /* Is this the first page ? */ if (VPID_EQ (addr_vpid_ptr, ovf_vpid)) { /* This is the first part */ first_part = (OVERFLOW_FIRST_PART *) addr.pgptr; old_length = first_part->length; copyto = (char *) first_part->data; next_vpid = first_part->next_vpid; hdr_length = offsetof (OVERFLOW_FIRST_PART, data); if ((length + hdr_length) > DB_PAGESIZE) { copy_length = DB_PAGESIZE - hdr_length; } else { copy_length = length; } /* Log before image */ if (hdr_length + old_length > DB_PAGESIZE) { log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr, DB_PAGESIZE, addr.pgptr); old_length -= DB_PAGESIZE - hdr_length; } else { log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr, hdr_length + old_length, addr.pgptr); old_length = 0; } /* Modify the new length */ first_part->length = length; /* notify the first part of overflow recdes */ log_append_empty_record (thread_p, LOG_DUMMY_OVF_RECORD); } else { rest_parts = (OVERFLOW_REST_PART *) addr.pgptr; copyto = (char *) rest_parts->data; if (isnewpage == true) { VPID_SET_NULL (&next_vpid); rest_parts->next_vpid = next_vpid; } else { next_vpid = rest_parts->next_vpid; } hdr_length = offsetof (OVERFLOW_REST_PART, data); if ((length + hdr_length) > DB_PAGESIZE) { copy_length = DB_PAGESIZE - hdr_length; } else { copy_length = length; } if (old_length > 0) { if (hdr_length + old_length > DB_PAGESIZE) { log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr, DB_PAGESIZE, addr.pgptr); old_length -= DB_PAGESIZE - hdr_length; } else { log_append_undo_data (thread_p, RVOVF_PAGE_UPDATE, &addr, hdr_length + old_length, addr.pgptr); old_length = 0; } } } memcpy (copyto, data, copy_length); data += copy_length; length -= copy_length; log_append_redo_data (thread_p, RVOVF_PAGE_UPDATE, &addr, copy_length + hdr_length, (char *) addr.pgptr); if (length > 0) { /* Need more pages... Get next page */ if (VPID_ISNULL (&next_vpid)) { /* We need to allocate a new page */ if (file_alloc_pages (thread_p, ovf_vfid, &next_vpid, 1, addr_vpid_ptr, NULL, NULL) == NULL) { pgbuf_set_dirty (thread_p, addr.pgptr, FREE); addr.pgptr = NULL; goto exit_on_error; } recv.new_vpid = next_vpid; log_append_undoredo_data (thread_p, RVOVF_NEWPAGE_LINK, &addr, sizeof (recv), sizeof (next_vpid), &recv, &next_vpid); isnewpage = true; /* So that its link can be set to NULL */ /* This logical undo is to remove the page in case of rollback */ if (file_is_new_file (thread_p, ovf_vfid) == FILE_OLD_FILE) { /* we don't do undo logging for new files */ log_append_undo_data (thread_p, RVOVF_NEWPAGE_LOGICAL_UNDO, &logical_undoaddr, sizeof (recv), &recv); } if (rest_parts == NULL) { /* This is the first part */ first_part->next_vpid = next_vpid; } else { /* This is part of rest part */ rest_parts->next_vpid = next_vpid; } } pgbuf_set_dirty (thread_p, addr.pgptr, FREE); addr.pgptr = NULL; } else { /* The content of the data has been copied. We don't need more pages. Deallocate any additional pages */ VPID_SET_NULL (&tmp_vpid); log_append_undoredo_data (thread_p, RVOVF_CHANGE_LINK, &addr, sizeof (next_vpid), sizeof (next_vpid), &next_vpid, &tmp_vpid); if (rest_parts == NULL) { /* This is the first part */ VPID_SET_NULL (&first_part->next_vpid); } else { /* This is part of rest part */ VPID_SET_NULL (&rest_parts->next_vpid); } pgbuf_set_dirty (thread_p, addr.pgptr, FREE); addr.pgptr = NULL; while (!(VPID_ISNULL (&next_vpid))) { addr.pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH); if (addr.pgptr == NULL) { goto exit_on_error; } tmp_vpid = next_vpid; rest_parts = (OVERFLOW_REST_PART *) addr.pgptr; next_vpid = rest_parts->next_vpid; if (pgbuf_invalidate (thread_p, addr.pgptr) != NO_ERROR) { goto exit_on_error; } addr.pgptr = NULL; if (file_dealloc_page (thread_p, ovf_vfid, &tmp_vpid) != NO_ERROR) { goto exit_on_error; } } break; } } return ovf_vpid; exit_on_error: return NULL; }
/* * overflow_dump () - Dump an overflow object in ascii * return: NO_ERROR * ovf_vpid(in): Overflow address */ int overflow_dump (THREAD_ENTRY * thread_p, FILE * fp, VPID * ovf_vpid) { OVERFLOW_FIRST_PART *first_part; OVERFLOW_REST_PART *rest_parts; PAGE_PTR pgptr = NULL; VPID next_vpid; int remain_length, dump_length; char *dumpfrom; int i; int ret = NO_ERROR; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ next_vpid = *ovf_vpid; pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { return ((ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret; } first_part = (OVERFLOW_FIRST_PART *) pgptr; remain_length = first_part->length; dumpfrom = (char *) first_part->data; next_vpid = first_part->next_vpid; while (remain_length > 0) { dump_length = (int) ((dumpfrom + remain_length > (char *) pgptr + DB_PAGESIZE) ? DB_PAGESIZE - (dumpfrom - (char *) pgptr) : remain_length); for (i = 0; i < dump_length; i++) { (void) fputc (*dumpfrom++, fp); } remain_length -= dump_length; if (remain_length > 0) { pgbuf_unfix_and_init (thread_p, pgptr); if (VPID_ISNULL (&next_vpid)) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_HEAP_OVFADDRESS_CORRUPTED, 3, ovf_vpid->volid, ovf_vpid->pageid, NULL_SLOTID); return ER_HEAP_OVFADDRESS_CORRUPTED; } pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { return ((ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret; } rest_parts = (OVERFLOW_REST_PART *) pgptr; dumpfrom = (char *) rest_parts->data; next_vpid = rest_parts->next_vpid; } } pgbuf_unfix_and_init (thread_p, pgptr); return ret; }
/* * overflow_get_capacity () - Find the current storage facts/capacity of given * overflow rec * return: NO_ERROR * ovf_vpid(in): Overflow address * ovf_size(out): Length of overflow object * ovf_num_pages(out): Total number of overflow pages * ovf_overhead(out): System overhead for overflow record * ovf_free_space(out): Free space for exapnsion of the overflow rec */ int overflow_get_capacity (THREAD_ENTRY * thread_p, const VPID * ovf_vpid, int *ovf_size, int *ovf_num_pages, int *ovf_overhead, int *ovf_free_space) { OVERFLOW_FIRST_PART *first_part; OVERFLOW_REST_PART *rest_parts; PAGE_PTR pgptr = NULL; VPID next_vpid; int remain_length; int hdr_length; int ret = NO_ERROR; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ next_vpid = *ovf_vpid; pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { return ER_FAILED; } first_part = (OVERFLOW_FIRST_PART *) pgptr; remain_length = first_part->length; *ovf_size = first_part->length; *ovf_num_pages = 0; *ovf_overhead = 0; *ovf_free_space = 0; hdr_length = offsetof (OVERFLOW_FIRST_PART, data); next_vpid = first_part->next_vpid; while (remain_length > 0) { if (remain_length > DB_PAGESIZE) { remain_length -= DB_PAGESIZE - hdr_length; } else { *ovf_free_space = DB_PAGESIZE - remain_length; remain_length = 0; } *ovf_num_pages += 1; *ovf_overhead += hdr_length; if (remain_length > 0) { pgbuf_unfix_and_init (thread_p, pgptr); if (VPID_ISNULL (&next_vpid)) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_HEAP_OVFADDRESS_CORRUPTED, 3, ovf_vpid->volid, ovf_vpid->pageid, NULL_SLOTID); ret = ER_HEAP_OVFADDRESS_CORRUPTED; goto exit_on_error; } pgptr = pgbuf_fix (thread_p, &next_vpid, OLD_PAGE, PGBUF_LATCH_READ, PGBUF_UNCONDITIONAL_LATCH); if (pgptr == NULL) { goto exit_on_error; } rest_parts = (OVERFLOW_REST_PART *) pgptr; hdr_length = offsetof (OVERFLOW_REST_PART, data); next_vpid = rest_parts->next_vpid; } } pgbuf_unfix_and_init (thread_p, pgptr); return ret; exit_on_error: *ovf_size = 0; *ovf_num_pages = 0; *ovf_overhead = 0; *ovf_free_space = 0; return (ret == NO_ERROR && (ret = er_errid ()) == NO_ERROR) ? ER_FAILED : ret; }
/* * overflow_insert () - Insert a multipage data in overflow * return: ovf_vpid on success or NULL on failure * ovf_vfid(in): File where the overflow data is going to be stored * ovf_vpid(out): Overflow address * recdes(in): Record descriptor * * Note: Data in overflow is composed of several pages. Pages in the overflow * area are not shared among other pieces of overflow data. * * -------------------------------- ------------------------ * |Next_vpid |Length|... data ...| ... --> |Next_vpid|... data ...| * -------------------------------- ------------------------ * * Single link list of pages. * The length of the multipage data is stored on its first overflow page * * Overflow pages are not locked in any mode since they are not shared * by other pieces of data and its address is only know by accessing the * relocation overflow record data which has been appropriately locked. */ VPID * overflow_insert (THREAD_ENTRY * thread_p, const VFID * ovf_vfid, VPID * ovf_vpid, RECDES * recdes) { PAGE_PTR vfid_fhdr_pgptr = NULL; OVERFLOW_FIRST_PART *first_part; OVERFLOW_REST_PART *rest_parts; OVERFLOW_RECV_LINKS undo_recv; char *copyto; int length, copy_length; INT32 npages = 0; char *data; int alloc_nth; LOG_DATA_ADDR addr; LOG_DATA_ADDR logical_undoaddr; int i; VPID *vpids, fhdr_vpid; VPID vpids_buffer[OVERFLOW_ALLOCVPID_ARRAY_SIZE + 1]; FILE_ALLOC_VPIDS alloc_vpids; /* * We don't need to lock the overflow pages since these pages are not * shared among several pieces of overflow data. The overflow pages are * know by accessing the relocation-overflow record with the appropiate lock */ addr.vfid = ovf_vfid; addr.offset = 0; logical_undoaddr.vfid = ovf_vfid; logical_undoaddr.offset = 0; logical_undoaddr.pgptr = NULL; undo_recv.ovf_vfid = *ovf_vfid; /* * Temporary: * Lock the file header, so I am the only one changing the file table * of allocated pages. This is needed since this function is using * file_find_nthpages, which could give me not the expected page, if someone * else remove pages, after the initial allocation. */ fhdr_vpid.volid = ovf_vfid->volid; fhdr_vpid.pageid = ovf_vfid->fileid; vfid_fhdr_pgptr = pgbuf_fix (thread_p, &fhdr_vpid, OLD_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH); if (vfid_fhdr_pgptr == NULL) { return NULL; } /* * Guess the number of pages. The total number of pages is found by * dividing length by pagesize - the smallest header. Then, we make sure * that this estimate is correct. */ length = recdes->length - (DB_PAGESIZE - (int) offsetof (OVERFLOW_FIRST_PART, data)); if (length > 0) { i = DB_PAGESIZE - offsetof (OVERFLOW_REST_PART, data); npages = 1 + CEIL_PTVDIV (length, i); } else { npages = 1; } if (npages > OVERFLOW_ALLOCVPID_ARRAY_SIZE) { vpids = (VPID *) malloc ((npages + 1) * sizeof (VPID)); if (vpids == NULL) { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (npages + 1) * sizeof (VPID)); pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return NULL; } } else { vpids = vpids_buffer; } #if !defined(NDEBUG) for (i = 0; i < npages; i++) { VPID_SET_NULL (&vpids[i]); } #endif VPID_SET_NULL (&vpids[npages]); alloc_vpids.vpids = vpids; alloc_vpids.index = 0; /* * We do not initialize the pages during allocation since they are not * pointed by anyone until we return from this function, at that point * they are initialized. */ if (file_alloc_pages_as_noncontiguous (thread_p, ovf_vfid, vpids, &alloc_nth, npages, NULL, NULL, NULL, &alloc_vpids) == NULL) { if (vpids != vpids_buffer) { free_and_init (vpids); } pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return NULL; } assert (alloc_vpids.index == npages); #if !defined(NDEBUG) for (i = 0; i < npages; i++) { assert (!VPID_ISNULL (&vpids[i])); } #endif *ovf_vpid = vpids[0]; /* Copy the content of the data */ data = recdes->data; length = recdes->length; for (i = 0; i < npages; i++) { addr.pgptr = pgbuf_fix (thread_p, &vpids[i], NEW_PAGE, PGBUF_LATCH_WRITE, PGBUF_UNCONDITIONAL_LATCH); if (addr.pgptr == NULL) { goto exit_on_error; } /* Is this the first page ? */ if (i == 0) { /* This is the first part */ first_part = (OVERFLOW_FIRST_PART *) addr.pgptr; first_part->next_vpid = vpids[i + 1]; first_part->length = length; copyto = (char *) first_part->data; copy_length = DB_PAGESIZE - offsetof (OVERFLOW_FIRST_PART, data); if (length < copy_length) { copy_length = length; } /* notify the first part of overflow recdes */ log_append_empty_record (thread_p, LOG_DUMMY_OVF_RECORD); } else { rest_parts = (OVERFLOW_REST_PART *) addr.pgptr; rest_parts->next_vpid = vpids[i + 1]; copyto = (char *) rest_parts->data; copy_length = DB_PAGESIZE - offsetof (OVERFLOW_REST_PART, data); if (length < copy_length) { copy_length = length; } } memcpy (copyto, data, copy_length); data += copy_length; length -= copy_length; pgbuf_get_vpid (addr.pgptr, &undo_recv.new_vpid); if (file_is_new_file (thread_p, ovf_vfid) == FILE_OLD_FILE) { /* we don't do undo logging for new files */ log_append_undo_data (thread_p, RVOVF_NEWPAGE_LOGICAL_UNDO, &logical_undoaddr, sizeof (undo_recv), &undo_recv); } log_append_redo_data (thread_p, RVOVF_NEWPAGE_INSERT, &addr, copy_length + CAST_BUFLEN (copyto - (char *) addr.pgptr), (char *) addr.pgptr); pgbuf_set_dirty (thread_p, addr.pgptr, FREE); addr.pgptr = NULL; } assert (length == 0); #if defined (CUBRID_DEBUG) if (length > 0) { er_log_debug (ARG_FILE_LINE, "ovf_insert: ** SYSTEM ERROR calculation" " of number of pages needed to store overflow data seems" " incorrect. Need no more than %d pages", npages); goto exit_on_error; } #endif /* * Temporary: * Unlock the file header, so I am the only one changing the file table * of allocated pages. This is needed since curently, I am using * file_find_nthpages, which could give me not the expected page, if someone * else remove pages. */ if (vpids != vpids_buffer) { free_and_init (vpids); } pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return ovf_vpid; exit_on_error: for (i = 0; i < npages; i++) { (void) file_dealloc_page (thread_p, ovf_vfid, &vpids[i]); } if (vpids != vpids_buffer) { free_and_init (vpids); } pgbuf_unfix (thread_p, vfid_fhdr_pgptr); return NULL; }
/* * cursor_get_list_file_page () - * return: * cursor_id(in/out): Cursor identifier * vpid(in): */ static int cursor_get_list_file_page (CURSOR_ID * cursor_id_p, VPID * vpid_p) { VPID in_vpid; int page_size; char *page_p; /* find page at buffer area */ if (VPID_EQ (vpid_p, &cursor_id_p->current_vpid)) { /* * current_vpid can indicate one of pages in buffer area, * so do not assign buffer as head of buffer area */ ; } else { cursor_id_p->buffer = NULL; if (cursor_id_p->buffer_filled_size > 0) { /* it received a page from server */ if (VPID_EQ (vpid_p, &cursor_id_p->header_vpid)) { /* in case of header vpid in buffer area */ cursor_id_p->buffer = cursor_id_p->buffer_area; } else { page_p = cursor_id_p->buffer_area; page_size = 0; while (page_size < (cursor_id_p->buffer_filled_size - CURSOR_BUFFER_SIZE)) { if (QFILE_GET_OVERFLOW_PAGE_ID (page_p) == NULL_PAGEID) { QFILE_GET_NEXT_VPID (&in_vpid, page_p); } else { QFILE_GET_OVERFLOW_VPID (&in_vpid, page_p); } if (VPID_ISNULL (&in_vpid)) { break; } else if (VPID_EQ (vpid_p, &in_vpid)) { cursor_id_p->buffer = page_p + CURSOR_BUFFER_SIZE; break; } page_p += CURSOR_BUFFER_SIZE; page_size += CURSOR_BUFFER_SIZE; } } } } /* if not found, get the page from server */ if (cursor_id_p->buffer == NULL) { if (qfile_get_list_file_page (cursor_id_p->query_id, vpid_p->volid, vpid_p->pageid, cursor_id_p->buffer_area, &cursor_id_p->buffer_filled_size) != NO_ERROR) { return er_errid (); } cursor_id_p->buffer = cursor_id_p->buffer_area; QFILE_COPY_VPID (&cursor_id_p->header_vpid, vpid_p); } return NO_ERROR; }
/* * cursor_prev_tuple () - * return: NO_CURSOR_SUCCESS, DB_CURSOR_END, error_code * cursor_id(in/out): Cursor Identifier * Note: Makes the previous tuple in the LIST FILE referred by cursor * identifier the current active tuple of the cursor and returns * DB_CURSOR_SUCCESS. * * Note: if end_of_scan: DB_CURSOR_END, otherwise an error code is returned. */ int cursor_prev_tuple (CURSOR_ID * cursor_id_p) { cursor_initialize_current_tuple_value_position (cursor_id_p); if (cursor_id_p->position == C_BEFORE) { return DB_CURSOR_END; } else if (cursor_id_p->position == C_ON) { VPID prev_vpid; if (cursor_id_p->current_tuple_no > 0) { cursor_id_p->tuple_no--; cursor_id_p->current_tuple_no--; cursor_id_p->current_tuple_offset -= QFILE_GET_PREV_TUPLE_LENGTH (cursor_id_p->current_tuple_p); cursor_id_p->current_tuple_p -= QFILE_GET_PREV_TUPLE_LENGTH (cursor_id_p->current_tuple_p); cursor_id_p->current_tuple_length = QFILE_GET_TUPLE_LENGTH (cursor_id_p->current_tuple_p); } else if (QFILE_GET_PREV_PAGE_ID (cursor_id_p->buffer) != NULL_PAGEID) { QFILE_GET_PREV_VPID (&prev_vpid, cursor_id_p->buffer); if (cursor_fetch_page_having_tuple (cursor_id_p, &prev_vpid, LAST_TPL, 0) != NO_ERROR) { return DB_CURSOR_ERROR; } QFILE_COPY_VPID (&cursor_id_p->current_vpid, &prev_vpid); cursor_id_p->tuple_no--; } else { cursor_id_p->position = C_BEFORE; cursor_id_p->tuple_no = -1; return DB_CURSOR_END; } } else if (cursor_id_p->position == C_AFTER) { if (VPID_ISNULL (&(cursor_id_p->list_id.first_vpid))) { return DB_CURSOR_END; } if (cursor_fetch_page_having_tuple (cursor_id_p, &cursor_id_p->list_id.last_vpid, LAST_TPL, 0) != NO_ERROR) { return DB_CURSOR_ERROR; } QFILE_COPY_VPID (&cursor_id_p->current_vpid, &cursor_id_p->list_id.last_vpid); cursor_id_p->position = C_ON; cursor_id_p->tuple_no--; } else { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_UNKNOWN_CRSPOS, 0); return ER_QPROC_UNKNOWN_CRSPOS; } return DB_CURSOR_SUCCESS; }
/* * cursor_next_tuple () - * return: NO_CURSOR_SUCCESS, DB_CURSOR_END, error_code * cursor_id(in/out): Cursor Identifier * Note: Makes the next tuple in the LIST FILE referred by the cursor * identifier the current active tuple of the cursor and returns * DB_CURSOR_SUCCESS. * * Note: if end_of_scan: DB_CURSOR_END, otherwise an error code is returned. */ int cursor_next_tuple (CURSOR_ID * cursor_id_p) { cursor_initialize_current_tuple_value_position (cursor_id_p); if (cursor_id_p->position == C_BEFORE) { if (VPID_ISNULL (&(cursor_id_p->list_id.first_vpid))) { return DB_CURSOR_END; } if (cursor_fetch_page_having_tuple (cursor_id_p, &cursor_id_p->list_id.first_vpid, FIRST_TPL, 0) != NO_ERROR) { return DB_CURSOR_ERROR; } QFILE_COPY_VPID (&cursor_id_p->current_vpid, &cursor_id_p->list_id.first_vpid); /* * Setup the cursor so that we can proceed through the next "if" * statement w/o code duplication. */ cursor_id_p->position = C_ON; cursor_id_p->tuple_no = -1; cursor_id_p->current_tuple_no = -1; cursor_id_p->current_tuple_length = 0; } if (cursor_id_p->position == C_ON) { VPID next_vpid; if (cursor_id_p->current_tuple_no < cursor_id_p->buffer_tuple_count - 1) { cursor_id_p->tuple_no++; cursor_id_p->current_tuple_no++; cursor_id_p->current_tuple_offset += cursor_id_p->current_tuple_length; cursor_id_p->current_tuple_p += cursor_id_p->current_tuple_length; cursor_id_p->current_tuple_length = QFILE_GET_TUPLE_LENGTH (cursor_id_p->current_tuple_p); } else if (QFILE_GET_NEXT_PAGE_ID (cursor_id_p->buffer) != NULL_PAGEID) { QFILE_GET_NEXT_VPID (&next_vpid, cursor_id_p->buffer); if (cursor_fetch_page_having_tuple (cursor_id_p, &next_vpid, FIRST_TPL, 0) != NO_ERROR) { return DB_CURSOR_ERROR; } QFILE_COPY_VPID (&cursor_id_p->current_vpid, &next_vpid); cursor_id_p->tuple_no++; } else { cursor_id_p->position = C_AFTER; cursor_id_p->tuple_no = cursor_id_p->list_id.tuple_cnt; return DB_CURSOR_END; } } else if (cursor_id_p->position == C_AFTER) { return DB_CURSOR_END; } else { er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_QPROC_UNKNOWN_CRSPOS, 0); return ER_QPROC_UNKNOWN_CRSPOS; } return DB_CURSOR_SUCCESS; }