static void do_add (bool_t play, char * * title) { int list = aud_playlist_by_unique_id (playlist_id); int n_items = index_count (items); int n_selected = 0; Index * filenames = index_new (); Index * tuples = index_new (); for (int i = 0; i < n_items; i ++) { if (! selection->data[i]) continue; Item * item = index_get (items, i); for (int m = 0; m < item->matches->len; m ++) { int entry = g_array_index (item->matches, int, m); index_insert (filenames, -1, aud_playlist_entry_get_filename (list, entry)); index_insert (tuples, -1, aud_playlist_entry_get_tuple (list, entry, TRUE)); } n_selected ++; if (title && n_selected == 1) * title = item->name; } if (title && n_selected != 1) * title = NULL; aud_playlist_entry_insert_batch (aud_playlist_get_active (), -1, filenames, tuples, play); }
static void open_modules_for_path (const char * path) { GDir * folder = g_dir_open (path, 0, NULL); if (! folder) { fprintf (stderr, "ladspa: Failed to read folder %s: %s\n", path, strerror (errno)); return; } const char * name; while ((name = g_dir_read_name (folder))) { if (! str_has_suffix_nocase (name, G_MODULE_SUFFIX)) continue; char * filename = filename_build (path, name); void * handle = open_module (filename); if (handle) index_insert (modules, -1, handle); str_unref (filename); } g_dir_close (folder); }
static PluginData * open_plugin (const char * path, const LADSPA_Descriptor * desc) { const char * slash = strrchr (path, G_DIR_SEPARATOR); g_return_val_if_fail (slash && slash[1], NULL); g_return_val_if_fail (desc->Label && desc->Name, NULL); PluginData * plugin = g_slice_new (PluginData); plugin->path = g_strdup (slash + 1); plugin->desc = desc; plugin->controls = index_new (); plugin->in_ports = g_array_new (0, 0, sizeof (int)); plugin->out_ports = g_array_new (0, 0, sizeof (int)); plugin->selected = 0; for (int i = 0; i < desc->PortCount; i ++) { if (LADSPA_IS_PORT_CONTROL (desc->PortDescriptors[i])) { ControlData * control = parse_control (desc, i); if (control) index_insert (plugin->controls, -1, control); } else if (LADSPA_IS_PORT_AUDIO (desc->PortDescriptors[i]) && LADSPA_IS_PORT_INPUT (desc->PortDescriptors[i])) g_array_append_val (plugin->in_ports, i); else if (LADSPA_IS_PORT_AUDIO (desc->PortDescriptors[i]) && LADSPA_IS_PORT_OUTPUT (desc->PortDescriptors[i])) g_array_append_val (plugin->out_ports, i); } return plugin; }
void PPSWorkload::init_tab_suppliers() { char * padding = new char[100]; for (int i = 0; i < 100; i++) { padding[i] = 'z'; } for (UInt32 id = 1; id <= g_max_supplier_key; id++) { if (GET_NODE_ID(suppliers_to_partition(id)) != g_node_id) continue; row_t * row; uint64_t row_id; t_suppliers->get_new_row(row, 0, row_id); row->set_primary_key(id); row->set_value(0,id); row->set_value(FIELD1,padding); row->set_value(FIELD2,padding); row->set_value(FIELD3,padding); row->set_value(FIELD4,padding); row->set_value(FIELD5,padding); row->set_value(FIELD6,padding); row->set_value(FIELD7,padding); row->set_value(FIELD8,padding); row->set_value(FIELD9,padding); row->set_value(FIELD10,padding); index_insert(i_suppliers, id, row, suppliers_to_partition(id)); } }
static void search_cb (void * key, void * _item, void * _state) { Item * item = _item; SearchState * state = _state; if (index_count (state->items[item->field]) > MAX_RESULTS) return; int oldmask = state->mask; int count = index_count (search_terms); for (int t = 0, bit = 1; t < count; t ++, bit <<= 1) { if (! (state->mask & bit)) continue; /* skip term if it is already found */ if (strstr (item->folded, index_get (search_terms, t))) state->mask &= ~bit; /* we found it */ else if (! item->children) break; /* quit early if there are no children to search */ } if (! state->mask) index_insert (state->items[item->field], -1, item); if (item->children) g_hash_table_foreach (item->children, search_cb, state); state->mask = oldmask; }
void PPSWorkload::init_tab_products() { char * padding = new char[100]; for (int i = 0; i < 100; i++) { padding[i] = 'z'; } for (UInt32 id = 1; id <= g_max_product_key; id++) { if (GET_NODE_ID(products_to_partition(id)) != g_node_id) continue; row_t * row; uint64_t row_id; t_products->get_new_row(row, 0, row_id); row->set_primary_key(id); row->set_value(0,id); row->set_value(FIELD1,padding); row->set_value(FIELD2,padding); row->set_value(FIELD3,padding); row->set_value(FIELD4,padding); row->set_value(FIELD5,padding); row->set_value(FIELD6,padding); row->set_value(FIELD7,padding); row->set_value(FIELD8,padding); row->set_value(FIELD9,padding); row->set_value(FIELD10,padding); index_insert(i_products, id, row, products_to_partition(id)); DEBUG("PRODUCTS added (%d, ...)\n",id); } }
/* * _bitmap_insert_lov() -- insert a new data into the given heap and index. */ void _bitmap_insert_lov(Relation lovHeap, Relation lovIndex, Datum *datum, bool *nulls, bool use_wal __attribute__((unused))) { TupleDesc tupDesc; HeapTuple tuple; bool result; Datum *indexDatum; bool *indexNulls; tupDesc = RelationGetDescr(lovHeap); /* insert this tuple into the heap */ tuple = heap_form_tuple(tupDesc, datum, nulls); frozen_heap_insert(lovHeap, tuple); /* insert a new tuple into the index */ indexDatum = palloc0((tupDesc->natts - 2) * sizeof(Datum)); indexNulls = palloc0((tupDesc->natts - 2) * sizeof(bool)); memcpy(indexDatum, datum, (tupDesc->natts - 2) * sizeof(Datum)); memcpy(indexNulls, nulls, (tupDesc->natts - 2) * sizeof(bool)); result = index_insert(lovIndex, indexDatum, indexNulls, &(tuple->t_self), lovHeap, true); pfree(indexDatum); pfree(indexNulls); Assert(result); heap_freetuple(tuple); }
void tpcc_wl::init_tab_dist(uint64_t wid) { for (uint64_t did = 1; did <= DIST_PER_WARE; did++) { row_t * row; uint64_t row_id; t_district->get_new_row(row, 0, row_id); row->set_primary_key(did); row->set_value(D_ID, did); row->set_value(D_W_ID, wid); char name[10]; MakeAlphaString(6, 10, name); row->set_value(D_NAME, name); char street[20]; MakeAlphaString(10, 20, street); row->set_value(D_STREET_1, street); MakeAlphaString(10, 20, street); row->set_value(D_STREET_2, street); MakeAlphaString(10, 20, street); row->set_value(D_CITY, street); char state[2]; MakeAlphaString(2, 2, state); /* State */ row->set_value(D_STATE, state); char zip[9]; MakeNumberString(9, 9, zip); /* Zip */ row->set_value(D_ZIP, zip); double tax = (double)URand(0L,200L)/1000.0; double w_ytd=30000.00; row->set_value(D_TAX, tax); row->set_value(D_YTD, w_ytd); row->set_value(D_NEXT_O_ID, 3001); index_insert(i_district, distKey(did, wid), row, wh_to_part(wid)); } }
static void * open_module (const char * path) { GModule * handle = g_module_open (path, G_MODULE_BIND_LOCAL); if (! handle) { fprintf (stderr, "ladspa: Failed to open module %s: %s\n", path, g_module_error ()); return NULL; } void * sym; if (! g_module_symbol (handle, "ladspa_descriptor", & sym)) { fprintf (stderr, "ladspa: Not a valid LADSPA module: %s\n", path); g_module_close (handle); return NULL; } LADSPA_Descriptor_Function descfun = (LADSPA_Descriptor_Function) sym; const LADSPA_Descriptor * desc; for (int i = 0; (desc = descfun (i)); i ++) { PluginData * plugin = open_plugin (path, desc); if (plugin) index_insert (plugins, -1, plugin); } return handle; }
LoadedPlugin * enable_plugin_locked (PluginData * plugin) { LoadedPlugin * loaded = g_slice_new (LoadedPlugin); loaded->plugin = plugin; loaded->selected = 0; int count = index_count (plugin->controls); loaded->values = g_malloc (sizeof (float) * count); for (int i = 0; i < count; i ++) { ControlData * control = index_get (plugin->controls, i); loaded->values[i] = control->def; } loaded->active = 0; loaded->instances = NULL; loaded->in_bufs = NULL; loaded->out_bufs = NULL; loaded->settings_win = NULL; index_insert (loadeds, -1, loaded); return loaded; }
void tpcc_wl::init_tab_wh(uint32_t wid) { assert(wid >= 1 && wid <= g_num_wh); row_t * row; uint64_t row_id; t_warehouse->get_new_row(row, 0, row_id); row->set_primary_key(wid); row->set_value(W_ID, wid); char name[10]; MakeAlphaString(6, 10, name, wid-1); row->set_value(W_NAME, name); char street[20]; MakeAlphaString(10, 20, street, wid-1); row->set_value(W_STREET_1, street); MakeAlphaString(10, 20, street, wid-1); row->set_value(W_STREET_2, street); MakeAlphaString(10, 20, street, wid-1); row->set_value(W_CITY, street); char state[2]; MakeAlphaString(2, 2, state, wid-1); /* State */ row->set_value(W_STATE, state); char zip[9]; MakeNumberString(9, 9, zip, wid-1); /* Zip */ row->set_value(W_ZIP, zip); double tax = (double)URand(0L,200L,wid-1)/1000.0; double w_ytd=300000.00; row->set_value(W_TAX, tax); row->set_value(W_YTD, w_ytd); index_insert(i_warehouse, wid, row, wh_to_part(wid)); return; }
int git_index_append(git_index *index, const char *path, int stage) { int error; git_index_entry entry; if ((error = index_init_entry(&entry, index, path, stage)) < GIT_SUCCESS) return git__rethrow(error, "Failed to append to index"); return index_insert(index, &entry, 0); }
static void shift_rows (void * user, int row, int before) { int rows = index_count (user); g_return_if_fail (row >= 0 && row < rows); g_return_if_fail (before >= 0 && before <= rows); if (before == row) return; Index * move = index_new (); Index * others = index_new (); int begin, end; if (before < row) { begin = before; end = row + 1; while (end < rows && ((Column *) index_get (user, end))->selected) end ++; } else { begin = row; while (begin > 0 && ((Column *) index_get (user, begin - 1))->selected) begin --; end = before; } for (int i = begin; i < end; i ++) { Column * c = index_get (user, i); index_insert (c->selected ? move : others, -1, c); } if (before < row) { index_copy_insert (others, 0, move, -1, -1); index_free (others); } else { index_copy_insert (move, 0, others, -1, -1); index_free (move); move = others; } index_copy_set (move, 0, user, begin, end - begin); index_free (move); GtkWidget * list = (user == chosen) ? chosen_list : avail_list; audgui_list_update_rows (list, begin, end - begin); audgui_list_update_selection (list, begin, end - begin); }
/* * ExecInsertCQMatRelIndexTuples * * This is a trimmed-down version of ExecInsertIndexTuples */ void ExecInsertCQMatRelIndexTuples(ResultRelInfo *indstate, TupleTableSlot *slot, EState *estate) { int i; int numIndexes; RelationPtr relationDescs; Relation heapRelation; IndexInfo **indexInfoArray; Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; HeapTuple tup; /* bail if there are no indexes to update */ numIndexes = indstate->ri_NumIndices; if (numIndexes == 0) return; tup = ExecMaterializeSlot(slot); /* HOT update does not require index inserts */ if (HeapTupleIsHeapOnly(tup)) return; relationDescs = indstate->ri_IndexRelationDescs; indexInfoArray = indstate->ri_IndexRelationInfo; heapRelation = indstate->ri_RelationDesc; /* * for each index, form and insert the index tuple */ for (i = 0; i < numIndexes; i++) { IndexInfo *indexInfo; indexInfo = indexInfoArray[i]; /* If the index is marked as read-only, ignore it */ if (!indexInfo->ii_ReadyForInserts) continue; /* Index expressions need an EState to be eval'd in */ if (indexInfo->ii_Expressions) { ExprContext *econtext = GetPerTupleExprContext(estate); econtext->ecxt_scantuple = slot; } FormIndexDatum(indexInfo, slot, estate, values, isnull); index_insert(relationDescs[i], values, isnull, &(tup->t_self), heapRelation, relationDescs[i]->rd_index->indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); } }
void pw_col_save (void) { Index * index = index_new (); for (int i = 0; i < pw_num_cols; i ++) index_insert (index, -1, (void *) pw_col_keys[pw_cols[i]]); char * columns = index_to_str_list (index, " "); aud_set_str ("gtkui", "playlist_columns", columns); str_unref (columns); index_free (index); }
static void begin_add (const char * path) { int list = get_playlist (FALSE, FALSE); if (list < 0) list = create_playlist (); aud_set_str ("search-tool", "path", path); char * uri = filename_to_uri (path); g_return_if_fail (uri); if (! g_str_has_suffix (uri, "/")) { SCONCAT2 (temp, uri, "/"); str_unref (uri); uri = str_get (temp); } destroy_added_table (); added_table = g_hash_table_new_full ((GHashFunc) str_hash, (GEqualFunc) str_equal, (GDestroyNotify) str_unref, NULL); int entries = aud_playlist_entry_count (list); for (int entry = 0; entry < entries; entry ++) { char * filename = aud_playlist_entry_get_filename (list, entry); if (g_str_has_prefix (filename, uri) && ! g_hash_table_contains (added_table, filename)) { aud_playlist_entry_set_selected (list, entry, FALSE); g_hash_table_insert (added_table, filename, NULL); } else { aud_playlist_entry_set_selected (list, entry, TRUE); str_unref (filename); } } aud_playlist_delete_selected (list); aud_playlist_remove_failed (list); Index * add = index_new (); index_insert (add, -1, uri); aud_playlist_entry_insert_filtered (list, -1, add, NULL, filter_cb, NULL, FALSE); adding = TRUE; }
int set(char *key,char *value,int exptime){ //store save int fieldId = 0; long blockPos; //printf("store_save \n"); store_save(key,value,exptime,&fieldId,&blockPos); //printf("store return fieldId:%d,blockPos:%d\n", fieldId,blockPos); //index index_insert(key,fieldId,blockPos); return 0; }
static int fulltextUpdate(sqlite3_vtab *pVtab, int nArg, sqlite3_value **ppArg, sqlite_int64 *pRowid){ fulltext_vtab *v = (fulltext_vtab *) pVtab; if( nArg<2 ){ return index_delete(v, sqlite3_value_int64(ppArg[0])); } if( sqlite3_value_type(ppArg[0]) != SQLITE_NULL ){ return SQLITE_ERROR; /* an update; not yet supported */ } assert( nArg==3 ); /* ppArg[1] = rowid, ppArg[2] = content */ return index_insert(v, ppArg[1], (const char *)sqlite3_value_text(ppArg[2]), pRowid); }
static void equalizerwin_save_preset (Index * list, const char * name, const char * filename) { int p = equalizerwin_find_preset (list, name); EqualizerPreset * preset = (p >= 0) ? index_get (list, p) : NULL; if (! preset) { preset = aud_equalizer_preset_new (name); index_insert (list, -1, preset); } equalizerwin_update_preset (preset); aud_equalizer_write_presets (list, filename); }
// TODO ITEM table is assumed to be in partition 0 void tpcc_wl::init_tab_item() { for (UInt32 i = 1; i <= g_max_items; i++) { row_t * row; uint64_t row_id; t_item->get_new_row(row, 0, row_id); row->set_primary_key(i); row->set_value(I_ID, i); row->set_value(I_IM_ID, URand(1L,10000L, 0)); char name[24]; MakeAlphaString(14, 24, name, 0); row->set_value(I_NAME, name); row->set_value(I_PRICE, URand(1, 100, 0)); char data[50]; MakeAlphaString(26, 50, data, 0); // TODO in TPCC, "original" should start at a random position if (RAND(10, 0) == 0) strcpy(data, "original"); row->set_value(I_DATA, data); index_insert(i_item, i, row, 0); } }
static void write_index(const char *filename) { struct index_node *index; char *line; FILE *cfile; cfile = fopen(filename, "w"); if (!cfile) fatal("Could not open %s for writing: %s\n", filename, strerror(errno)); index = index_create(); while((line = getline_wrapped(stdin, NULL))) { index_insert(index, line); free(line); } index_write(index, cfile); index_destroy(index); fclose(cfile); }
void tpcc_wl::init_tab_stock(uint64_t wid) { for (UInt32 sid = 1; sid <= g_max_items; sid++) { row_t * row; uint64_t row_id; t_stock->get_new_row(row, 0, row_id); row->set_primary_key(sid); row->set_value(S_I_ID, sid); row->set_value(S_W_ID, wid); row->set_value(S_QUANTITY, URand(10, 100)); row->set_value(S_REMOTE_CNT, 0); #if !TPCC_SMALL char s_dist[25]; char row_name[10] = "S_DIST_"; for (int i = 1; i <= 10; i++) { if (i < 10) { row_name[7] = '0'; row_name[8] = i + '0'; } else { row_name[7] = '1'; row_name[8] = '0'; } row_name[9] = '\0'; MakeAlphaString(24, 24, s_dist); row->set_value(row_name, s_dist); } row->set_value(S_YTD, 0); row->set_value(S_ORDER_CNT, 0); char s_data[50]; int len = MakeAlphaString(26, 50, s_data); if (rand() % 100 < 10) { int idx = URand(0, len - 8); strcpy(&s_data[idx], "original"); } row->set_value(S_DATA, s_data); #endif index_insert(i_stock, stockKey(sid, wid), row, wh_to_part(wid)); } }
static void transfer (Index * source) { Index * dest; GtkWidget * source_list, * dest_list; if (source == chosen) { dest = avail; source_list = chosen_list; dest_list = avail_list; } else { dest = chosen; source_list = avail_list; dest_list = chosen_list; } int source_rows = index_count (source); int dest_rows = index_count (dest); for (int row = 0; row < source_rows; ) { Column * c = index_get (source, row); if (! c->selected) { row ++; continue; } index_delete (source, row, 1); audgui_list_delete_rows (source_list, row, 1); source_rows --; index_insert (dest, -1, c); audgui_list_insert_rows (dest_list, dest_rows, 1); dest_rows ++; } }
void tpcc_wl::init_tab_wh() { if (WL_VERB) printf("[init] workload table.\n"); for (UInt32 wid = 1; wid <= g_num_wh; wid ++) { row_t * row; uint64_t row_id; t_warehouse->get_new_row(row, 0, row_id); row->set_primary_key(wid); row->set_value(W_ID, wid); char name[10]; MakeAlphaString(6, 10, name); row->set_value(W_NAME, name); char street[20]; MakeAlphaString(10, 20, street); row->set_value(W_STREET_1, street); MakeAlphaString(10, 20, street); row->set_value(W_STREET_2, street); MakeAlphaString(10, 20, street); row->set_value(W_CITY, street); char state[2]; MakeAlphaString(2, 2, state); /* State */ row->set_value(W_STATE, state); char zip[9]; MakeNumberString(9, 9, zip); /* Zip */ row->set_value(W_ZIP, zip); double tax = (double)URand(0L,200L)/1000.0; double w_ytd=300000.00; row->set_value(W_TAX, tax); row->set_value(W_YTD, w_ytd); index_insert(i_warehouse, wid, row, wh_to_part(wid)); } return; }
/* ---------- * toast_save_datum - * * Save one single datum into the secondary relation and return * a Datum reference for it. * ---------- */ static Datum toast_save_datum(Relation rel, Datum value, int options) { Relation toastrel; Relation toastidx; HeapTuple toasttup; TupleDesc toasttupDesc; Datum t_values[3]; bool t_isnull[3]; CommandId mycid = GetCurrentCommandId(true); struct varlena *result; struct varatt_external toast_pointer; struct { struct varlena hdr; char data[TOAST_MAX_CHUNK_SIZE]; /* make struct big enough */ int32 align_it; /* ensure struct is aligned well enough */ } chunk_data; int32 chunk_size; int32 chunk_seq = 0; char *data_p; int32 data_todo; Pointer dval = DatumGetPointer(value); /* * Open the toast relation and its index. We can use the index to check * uniqueness of the OID we assign to the toasted item, even though it has * additional columns besides OID. */ toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock); toasttupDesc = toastrel->rd_att; toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock); /* * Get the data pointer and length, and compute va_rawsize and va_extsize. * * va_rawsize is the size of the equivalent fully uncompressed datum, so * we have to adjust for short headers. * * va_extsize is the actual size of the data payload in the toast records. */ if (VARATT_IS_SHORT(dval)) { data_p = VARDATA_SHORT(dval); data_todo = VARSIZE_SHORT(dval) - VARHDRSZ_SHORT; toast_pointer.va_rawsize = data_todo + VARHDRSZ; /* as if not short */ toast_pointer.va_extsize = data_todo; } else if (VARATT_IS_COMPRESSED(dval)) { data_p = VARDATA(dval); data_todo = VARSIZE(dval) - VARHDRSZ; /* rawsize in a compressed datum is just the size of the payload */ toast_pointer.va_rawsize = VARRAWSIZE_4B_C(dval) + VARHDRSZ; toast_pointer.va_extsize = data_todo; /* Assert that the numbers look like it's compressed */ Assert(VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)); } else { data_p = VARDATA(dval); data_todo = VARSIZE(dval) - VARHDRSZ; toast_pointer.va_rawsize = VARSIZE(dval); toast_pointer.va_extsize = data_todo; } /* * Insert the correct table OID into the result TOAST pointer. * * Normally this is the actual OID of the target toast table, but during * table-rewriting operations such as CLUSTER, we have to insert the OID * of the table's real permanent toast table instead. rd_toastoid is set * if we have to substitute such an OID. */ if (OidIsValid(rel->rd_toastoid)) toast_pointer.va_toastrelid = rel->rd_toastoid; else toast_pointer.va_toastrelid = RelationGetRelid(toastrel); /* * Choose an unused OID within the toast table for this toast value. */ toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, RelationGetRelid(toastidx), (AttrNumber) 1); /* * Initialize constant parts of the tuple data */ t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid); t_values[2] = PointerGetDatum(&chunk_data); t_isnull[0] = false; t_isnull[1] = false; t_isnull[2] = false; /* * Split up the item into chunks */ while (data_todo > 0) { /* * Calculate the size of this chunk */ chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo); /* * Build a tuple and store it */ t_values[1] = Int32GetDatum(chunk_seq++); SET_VARSIZE(&chunk_data, chunk_size + VARHDRSZ); memcpy(VARDATA(&chunk_data), data_p, chunk_size); toasttup = heap_form_tuple(toasttupDesc, t_values, t_isnull); heap_insert(toastrel, toasttup, mycid, options, NULL); /* * Create the index entry. We cheat a little here by not using * FormIndexDatum: this relies on the knowledge that the index columns * are the same as the initial columns of the table. * * Note also that there had better not be any user-created index on * the TOAST table, since we don't bother to update anything else. */ index_insert(toastidx, t_values, t_isnull, &(toasttup->t_self), toastrel, toastidx->rd_index->indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); /* * Free memory */ heap_freetuple(toasttup); /* * Move on to next chunk */ data_todo -= chunk_size; data_p += chunk_size; } /* * Done - close toast relation */ index_close(toastidx, RowExclusiveLock); heap_close(toastrel, RowExclusiveLock); /* * Create the TOAST pointer value that we'll return */ result = (struct varlena *) palloc(TOAST_POINTER_SIZE); SET_VARSIZE_EXTERNAL(result, TOAST_POINTER_SIZE); memcpy(VARDATA_EXTERNAL(result), &toast_pointer, sizeof(toast_pointer)); return PointerGetDatum(result); }
db_result_t relation_insert(relation_t *rel, attribute_value_t *values) { attribute_t *attr; unsigned char record[rel->row_length]; unsigned char *ptr; attribute_value_t *value; db_result_t result; value = values; PRINTF("DB: Relation %s has a record size of %u bytes\n", rel->name, (unsigned)rel->row_length); ptr = record; PRINTF("DB: Insert ("); for(attr = list_head(rel->attributes); attr != NULL; attr = attr->next, value++) { /* Verify that the value is in the expected domain. An exception to this rule is that INT may be promoted to LONG. */ if(attr->domain != value->domain && !(attr->domain == DOMAIN_LONG && value->domain == DOMAIN_INT)) { PRINTF("DB: The value domain %d does not match the domain %d of attribute %s\n", value->domain, attr->domain, attr->name); return DB_RELATIONAL_ERROR; } /* Set the data area for removed attributes to 0. */ if(attr->flags & ATTRIBUTE_FLAG_INVALID) { memset(ptr, 0, attr->element_size); ptr += attr->element_size; continue; } result = db_value_to_phy((unsigned char *)ptr, attr, value); if(DB_ERROR(result)) { return result; } #if DEBUG switch(attr->domain) { case DOMAIN_INT: PRINTF("%s=%d", attr->name, VALUE_INT(value)); break; case DOMAIN_LONG: PRINTF("%s=%ld", attr->name, VALUE_LONG(value)); break; case DOMAIN_STRING: PRINTF("%s='%s", attr->name, VALUE_STRING(value)); break; default: PRINTF(")\nDB: Unhandled attribute domain: %d\n", attr->domain); return DB_TYPE_ERROR; } if(attr->next != NULL) { PRINTF(", "); } #endif /* DEBUG */ ptr += attr->element_size; if(attr->index != NULL) { if(DB_ERROR(index_insert(attr->index, value, rel->next_row))) { return DB_INDEX_ERROR; } } } PRINTF(")\n"); rel->cardinality++; rel->next_row++; return storage_put_row(rel, record); }
/* ---------- * toast_save_datum - * * Save one single datum into the secondary relation and return * a varattrib reference for it. * ---------- */ static Datum toast_save_datum(Relation rel, Datum value) { Relation toastrel; Relation toastidx; HeapTuple toasttup; InsertIndexResult idxres; TupleDesc toasttupDesc; Datum t_values[3]; char t_nulls[3]; varattrib *result; struct { struct varlena hdr; char data[TOAST_MAX_CHUNK_SIZE]; } chunk_data; int32 chunk_size; int32 chunk_seq = 0; char *data_p; int32 data_todo; /* * Create the varattrib reference */ result = (varattrib *) palloc(sizeof(varattrib)); result->va_header = sizeof(varattrib) | VARATT_FLAG_EXTERNAL; if (VARATT_IS_COMPRESSED(value)) { result->va_header |= VARATT_FLAG_COMPRESSED; result->va_content.va_external.va_rawsize = ((varattrib *) value)->va_content.va_compressed.va_rawsize; } else result->va_content.va_external.va_rawsize = VARATT_SIZE(value); result->va_content.va_external.va_extsize = VARATT_SIZE(value) - VARHDRSZ; result->va_content.va_external.va_valueid = newoid(); result->va_content.va_external.va_toastrelid = rel->rd_rel->reltoastrelid; /* * Initialize constant parts of the tuple data */ t_values[0] = ObjectIdGetDatum(result->va_content.va_external.va_valueid); t_values[2] = PointerGetDatum(&chunk_data); t_nulls[0] = ' '; t_nulls[1] = ' '; t_nulls[2] = ' '; /* * Get the data to process */ data_p = VARATT_DATA(value); data_todo = VARATT_SIZE(value) - VARHDRSZ; /* * Open the toast relation */ toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock); toasttupDesc = toastrel->rd_att; toastidx = index_open(toastrel->rd_rel->reltoastidxid); /* * Split up the item into chunks */ while (data_todo > 0) { /* * Calculate the size of this chunk */ chunk_size = Min(TOAST_MAX_CHUNK_SIZE, data_todo); /* * Build a tuple and store it */ t_values[1] = Int32GetDatum(chunk_seq++); VARATT_SIZEP(&chunk_data) = chunk_size + VARHDRSZ; memcpy(VARATT_DATA(&chunk_data), data_p, chunk_size); toasttup = heap_formtuple(toasttupDesc, t_values, t_nulls); if (!HeapTupleIsValid(toasttup)) elog(ERROR, "failed to build TOAST tuple"); simple_heap_insert(toastrel, toasttup); /* * Create the index entry. We cheat a little here by not using * FormIndexDatum: this relies on the knowledge that the index * columns are the same as the initial columns of the table. * * Note also that there had better not be any user-created index on * the TOAST table, since we don't bother to update anything else. */ idxres = index_insert(toastidx, t_values, t_nulls, &(toasttup->t_self), toastrel, toastidx->rd_index->indisunique); if (idxres == NULL) elog(ERROR, "failed to insert index entry for TOAST tuple"); /* * Free memory */ pfree(idxres); heap_freetuple(toasttup); /* * Move on to next chunk */ data_todo -= chunk_size; data_p += chunk_size; } /* * Done - close toast relation and return the reference */ index_close(toastidx); heap_close(toastrel, RowExclusiveLock); return PointerGetDatum(result); }
/* * IndexSpoolInsert - * * Copy from ExecInsertIndexTuples. */ static void IndexSpoolInsert(BTSpool **spools, TupleTableSlot *slot, ItemPointer tupleid, EState *estate, bool reindex) { ResultRelInfo *relinfo; int i; int numIndices; RelationPtr indices; IndexInfo **indexInfoArray; Relation heapRelation; ExprContext *econtext; /* * Get information from the result relation relinfo structure. */ relinfo = estate->es_result_relation_info; numIndices = relinfo->ri_NumIndices; indices = relinfo->ri_IndexRelationDescs; indexInfoArray = relinfo->ri_IndexRelationInfo; heapRelation = relinfo->ri_RelationDesc; /* * We will use the EState's per-tuple context for evaluating predicates * and index expressions (creating it if it's not already there). */ econtext = GetPerTupleExprContext(estate); /* Arrange for econtext's scan tuple to be the tuple under test */ econtext->ecxt_scantuple = slot; for (i = 0; i < numIndices; i++) { Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; IndexInfo *indexInfo; if (indices[i] == NULL) continue; /* Skip non-btree indexes on reindex mode. */ if (reindex && spools != NULL && spools[i] == NULL) continue; indexInfo = indexInfoArray[i]; /* If the index is marked as read-only, ignore it */ if (!indexInfo->ii_ReadyForInserts) continue; /* Check for partial index */ if (indexInfo->ii_Predicate != NIL) { List *predicate; /* * If predicate state not set up yet, create it (in the estate's * per-query context) */ predicate = indexInfo->ii_PredicateState; if (predicate == NIL) { predicate = (List *) ExecPrepareExpr((Expr *) indexInfo->ii_Predicate, estate); indexInfo->ii_PredicateState = predicate; } /* Skip this index-update if the predicate isn'loader satisfied */ if (!ExecQual(predicate, econtext, false)) continue; } FormIndexDatum(indexInfo, slot, estate, values, isnull); /* * Insert or spool the tuple. */ if (spools != NULL && spools[i] != NULL) { IndexTuple itup = index_form_tuple(RelationGetDescr(indices[i]), values, isnull); itup->t_tid = *tupleid; _bt_spool(itup, spools[i]); pfree(itup); } else { /* Insert one by one */ index_insert(indices[i], values, isnull, tupleid, heapRelation, indices[i]->rd_index->indisunique); } } }
/* * CatalogIndexInsert - insert index entries for one catalog tuple * * This should be called for each inserted or updated catalog tuple. * * This is effectively a cut-down version of ExecInsertIndexTuples. */ void CatalogIndexInsert(CatalogIndexState indstate, HeapTuple heapTuple) { int i; int numIndexes; RelationPtr relationDescs; Relation heapRelation; TupleTableSlot *slot; IndexInfo **indexInfoArray; Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; /* HOT update does not require index inserts */ if (HeapTupleIsHeapOnly(heapTuple)) return; /* * Get information from the state structure. Fall out if nothing to do. */ numIndexes = indstate->ri_NumIndices; if (numIndexes == 0) return; relationDescs = indstate->ri_IndexRelationDescs; indexInfoArray = indstate->ri_IndexRelationInfo; heapRelation = indstate->ri_RelationDesc; /* Need a slot to hold the tuple being examined */ slot = MakeSingleTupleTableSlot(RelationGetDescr(heapRelation)); ExecStoreTuple(heapTuple, slot, InvalidBuffer, false); /* * for each index, form and insert the index tuple */ for (i = 0; i < numIndexes; i++) { IndexInfo *indexInfo; indexInfo = indexInfoArray[i]; /* If the index is marked as read-only, ignore it */ if (!indexInfo->ii_ReadyForInserts) continue; /* * Expressional and partial indexes on system catalogs are not * supported, nor exclusion constraints, nor deferred uniqueness */ Assert(indexInfo->ii_Expressions == NIL); Assert(indexInfo->ii_Predicate == NIL); Assert(indexInfo->ii_ExclusionOps == NULL); Assert(relationDescs[i]->rd_index->indimmediate); /* * FormIndexDatum fills in its values and isnull parameters with the * appropriate values for the column(s) of the index. */ FormIndexDatum(indexInfo, slot, NULL, /* no expression eval to do */ values, isnull); /* * The index AM does the rest. */ index_insert(relationDescs[i], /* index relation */ values, /* array of index Datums */ isnull, /* is-null flags */ &(heapTuple->t_self), /* tid of heap tuple */ heapRelation, relationDescs[i]->rd_index->indisunique ? UNIQUE_CHECK_YES : UNIQUE_CHECK_NO); } ExecDropSingleTupleTableSlot(slot); }
/* * unique_key_recheck - trigger function to do a deferred uniqueness check. * * This now also does deferred exclusion-constraint checks, so the name is * somewhat historical. * * This is invoked as an AFTER ROW trigger for both INSERT and UPDATE, * for any rows recorded as potentially violating a deferrable unique * or exclusion constraint. * * This may be an end-of-statement check, a commit-time check, or a * check triggered by a SET CONSTRAINTS command. */ Datum unique_key_recheck(PG_FUNCTION_ARGS) { TriggerData *trigdata = (TriggerData *) fcinfo->context; const char *funcname = "unique_key_recheck"; HeapTuple new_row; ItemPointerData tmptid; Relation indexRel; IndexInfo *indexInfo; EState *estate; ExprContext *econtext; TupleTableSlot *slot; Datum values[INDEX_MAX_KEYS]; bool isnull[INDEX_MAX_KEYS]; /* * Make sure this is being called as an AFTER ROW trigger. Note: * translatable error strings are shared with ri_triggers.c, so resist the * temptation to fold the function name into them. */ if (!CALLED_AS_TRIGGER(fcinfo)) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), errmsg("function \"%s\" was not called by trigger manager", funcname))); if (!TRIGGER_FIRED_AFTER(trigdata->tg_event) || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), errmsg("function \"%s\" must be fired AFTER ROW", funcname))); /* * Get the new data that was inserted/updated. */ if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event)) new_row = trigdata->tg_trigtuple; else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) new_row = trigdata->tg_newtuple; else { ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), errmsg("function \"%s\" must be fired for INSERT or UPDATE", funcname))); new_row = NULL; /* keep compiler quiet */ } /* * If the new_row is now dead (ie, inserted and then deleted within our * transaction), we can skip the check. However, we have to be careful, * because this trigger gets queued only in response to index insertions; * which means it does not get queued for HOT updates. The row we are * called for might now be dead, but have a live HOT child, in which case * we still need to make the check. Therefore we have to use * heap_hot_search, not just HeapTupleSatisfiesVisibility as is done in * the comparable test in RI_FKey_check. * * This might look like just an optimization, because the index AM will * make this identical test before throwing an error. But it's actually * needed for correctness, because the index AM will also throw an error * if it doesn't find the index entry for the row. If the row's dead then * it's possible the index entry has also been marked dead, and even * removed. */ tmptid = new_row->t_self; if (!heap_hot_search(&tmptid, trigdata->tg_relation, SnapshotSelf, NULL)) { /* * All rows in the HOT chain are dead, so skip the check. */ return PointerGetDatum(NULL); } /* * Open the index, acquiring a RowExclusiveLock, just as if we were going * to update it. (This protects against possible changes of the index * schema, not against concurrent updates.) */ indexRel = index_open(trigdata->tg_trigger->tgconstrindid, RowExclusiveLock); indexInfo = BuildIndexInfo(indexRel); /* * The heap tuple must be put into a slot for FormIndexDatum. */ slot = MakeSingleTupleTableSlot(RelationGetDescr(trigdata->tg_relation)); ExecStoreTuple(new_row, slot, InvalidBuffer, false); /* * Typically the index won't have expressions, but if it does we need an * EState to evaluate them. We need it for exclusion constraints too, * even if they are just on simple columns. */ if (indexInfo->ii_Expressions != NIL || indexInfo->ii_ExclusionOps != NULL) { estate = CreateExecutorState(); econtext = GetPerTupleExprContext(estate); econtext->ecxt_scantuple = slot; } else estate = NULL; /* * Form the index values and isnull flags for the index entry that we need * to check. * * Note: if the index uses functions that are not as immutable as they are * supposed to be, this could produce an index tuple different from the * original. The index AM can catch such errors by verifying that it * finds a matching index entry with the tuple's TID. For exclusion * constraints we check this in check_exclusion_constraint(). */ FormIndexDatum(indexInfo, slot, estate, values, isnull); /* * Now do the appropriate check. */ if (indexInfo->ii_ExclusionOps == NULL) { /* * Note: this is not a real insert; it is a check that the index entry * that has already been inserted is unique. */ index_insert(indexRel, values, isnull, &(new_row->t_self), trigdata->tg_relation, UNIQUE_CHECK_EXISTING); } else { /* * For exclusion constraints we just do the normal check, but now it's * okay to throw error. */ check_exclusion_constraint(trigdata->tg_relation, indexRel, indexInfo, &(new_row->t_self), values, isnull, estate, false, false); } /* * If that worked, then this index entry is unique or non-excluded, and we * are done. */ if (estate != NULL) FreeExecutorState(estate); ExecDropSingleTupleTableSlot(slot); index_close(indexRel, RowExclusiveLock); return PointerGetDatum(NULL); }