void CControlSocket::Cancel() { if (GetCurrentCommandId() != Command::none) { if (GetCurrentCommandId() == Command::connect) DoClose(FZ_REPLY_CANCELED); else ResetOperation(FZ_REPLY_CANCELED); } }
/* * CopyCurrentSnapshot * Make a snapshot that is up-to-date as of the current instant, * and return a copy. * * The copy is palloc'd in the current memory context. */ Snapshot CopyCurrentSnapshot(void) { Snapshot currentSnapshot; Snapshot snapshot; if (QuerySnapshot == NULL) /* should not be first call in xact */ elog(ERROR, "no snapshot has been set"); /* Update the static struct */ currentSnapshot = GetSnapshotData(&CurrentSnapshotData, false); currentSnapshot->curcid = GetCurrentCommandId(); /* Make a copy */ snapshot = (Snapshot) palloc(sizeof(SnapshotData)); memcpy(snapshot, currentSnapshot, sizeof(SnapshotData)); if (snapshot->xcnt > 0) { snapshot->xip = (TransactionId *) palloc(snapshot->xcnt * sizeof(TransactionId)); memcpy(snapshot->xip, currentSnapshot->xip, snapshot->xcnt * sizeof(TransactionId)); } else snapshot->xip = NULL; return snapshot; }
int CRealControlSocket::ContinueConnect(const wxIPV4address *address) { LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CRealControlSocket::ContinueConnect(%p) m_pEngine=%p"), address, m_pEngine); if (GetCurrentCommandId() != cmd_connect || !m_pCurrentServer) { LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer); return DoClose(FZ_REPLY_INTERNALERROR); } if (!address) { LogMessage(::Error, _("Invalid hostname or host not found")); return DoClose(FZ_REPLY_ERROR | FZ_REPLY_CRITICALERROR); } CConnectOpData* pData; if (!m_pCurOpData || m_pCurOpData->opId != cmd_connect) pData = 0; else pData = static_cast<CConnectOpData *>(m_pCurOpData); const unsigned int port = pData ? pData->port : m_pCurrentServer->GetPort(); LogMessage(Status, _("Connecting to %s:%d..."), address->IPAddress().c_str(), port); wxIPV4address addr = *address; addr.Service(port); bool res = wxSocketClient::Connect(addr, false); if (!res && LastError() != wxSOCKET_WOULDBLOCK) return DoClose(); return FZ_REPLY_WOULDBLOCK; }
static Snapshot DtmGetSnapshot(Snapshot snapshot) { if (TransactionIdIsValid(DtmNextXid) && snapshot != &CatalogSnapshotData) { if (!DtmHasGlobalSnapshot && (snapshot != DtmLastSnapshot || DtmCurcid != GetCurrentCommandId(false))) { ArbiterGetSnapshot(DtmNextXid, &DtmSnapshot, &dtm->minXid); } DtmLastSnapshot = snapshot; DtmMergeWithGlobalSnapshot(snapshot); DtmCurcid = snapshot->curcid; if (!IsolationUsesXactSnapshot()) { /* Use single global snapshot during all transaction for repeatable read isolation level, * but obtain new global snapshot each time it is requested for read committed isolation level */ DtmHasGlobalSnapshot = false; } } else { /* For local transactions and catalog snapshots use default GetSnapshotData implementation */ snapshot = PgGetSnapshotData(snapshot); } DtmUpdateRecentXmin(snapshot); return snapshot; }
/* * Executor state preparation for evaluation of constraint expressions, * indexes and triggers. * * This is based on similar code in copy.c */ static EState * create_estate_for_relation(LogicalRepRelMapEntry *rel) { EState *estate; ResultRelInfo *resultRelInfo; RangeTblEntry *rte; estate = CreateExecutorState(); rte = makeNode(RangeTblEntry); rte->rtekind = RTE_RELATION; rte->relid = RelationGetRelid(rel->localrel); rte->relkind = rel->localrel->rd_rel->relkind; estate->es_range_table = list_make1(rte); resultRelInfo = makeNode(ResultRelInfo); InitResultRelInfo(resultRelInfo, rel->localrel, 1, NULL, 0); estate->es_result_relations = resultRelInfo; estate->es_num_result_relations = 1; estate->es_result_relation_info = resultRelInfo; estate->es_output_cid = GetCurrentCommandId(true); /* Triggers might need a slot */ if (resultRelInfo->ri_TrigDesc) estate->es_trig_tuple_slot = ExecInitExtraTupleSlot(estate, NULL); /* Prepare to catch AFTER triggers. */ AfterTriggerBeginQuery(); return estate; }
/* * transientrel_startup --- executor startup */ static void transientrel_startup(DestReceiver *self, int operation, TupleDesc typeinfo) { DR_transientrel *myState = (DR_transientrel *) self; Relation transientrel; transientrel = heap_open(myState->transientoid, NoLock); /* * Fill private fields of myState for use by later routines */ myState->transientrel = transientrel; myState->output_cid = GetCurrentCommandId(true); /* * We can skip WAL-logging the insertions, unless PITR or streaming * replication is in use. We can skip the FSM in any case. */ myState->hi_options = HEAP_INSERT_SKIP_FSM | HEAP_INSERT_FROZEN; if (!XLogIsNeeded()) myState->hi_options |= HEAP_INSERT_SKIP_WAL; myState->bistate = GetBulkInsertState(); /* Not using WAL requires smgr_targblock be initially invalid */ Assert(RelationGetTargetBlock(transientrel) == InvalidBlockNumber); }
void CRealControlSocket::OnClose() { LogMessage(Debug_Verbose, _T("CRealControlSocket::OnClose()")); if (GetCurrentCommandId() != cmd_connect) LogMessage(::Error, _("Disconnected from server")); DoClose(); }
/* * ExecCQMatViewInsert * * Insert a new row into a CV materialization table */ void ExecCQMatRelInsert(ResultRelInfo *ri, TupleTableSlot *slot, EState *estate) { HeapTuple tup = ExecMaterializeSlot(slot); heap_insert(ri->ri_RelationDesc, tup, GetCurrentCommandId(true), 0, NULL); ExecInsertCQMatRelIndexTuples(ri, slot, estate); }
/* * UpdateActiveSnapshotCommandId * * Update the current CID of the active snapshot. This can only be applied * to a snapshot that is not referenced elsewhere. */ void UpdateActiveSnapshotCommandId(void) { Assert(ActiveSnapshot != NULL); Assert(ActiveSnapshot->as_snap->active_count == 1); Assert(ActiveSnapshot->as_snap->regd_count == 0); ActiveSnapshot->as_snap->curcid = GetCurrentCommandId(false); }
/* * RegisterSmgrInvalidation * * As above, but register an smgr invalidation event. */ static void RegisterSmgrInvalidation(RelFileNode rnode) { AddSmgrInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, rnode); /* * As above, just in case there is not an associated catalog change. */ (void) GetCurrentCommandId(true); }
void CRealControlSocket::OnClose(int error) { LogMessage(MessageType::Debug_Verbose, _T("CRealControlSocket::OnClose(%d)"), error); if (GetCurrentCommandId() != Command::connect) { if (!error) LogMessage(MessageType::Error, _("Connection closed by server")); else LogMessage(MessageType::Error, _("Disconnected from server: %s"), CSocket::GetErrorDescription(error)); } DoClose(); }
int CHttpControlSocket::ContinueConnect() { LogMessage(__TFILE__, __LINE__, this, Debug_Verbose, _T("CHttpControlSocket::ContinueConnect() m_pEngine=%p"), m_pEngine); if (GetCurrentCommandId() != cmd_connect || !m_pCurrentServer) { LogMessage(Debug_Warning, _T("Invalid context for call to ContinueConnect(), cmd=%d, m_pCurrentServer=%p"), GetCurrentCommandId(), m_pCurrentServer); return DoClose(FZ_REPLY_INTERNALERROR); } ResetOperation(FZ_REPLY_OK); return FZ_REPLY_OK; }
/* * PushUpdatedSnapshot * As above, except we set the snapshot's CID to the current CID. */ void PushUpdatedSnapshot(Snapshot snapshot) { Snapshot newsnap; /* * We cannot risk modifying a snapshot that's possibly already used * elsewhere, so make a new copy to scribble on. */ newsnap = CopySnapshot(snapshot); newsnap->curcid = GetCurrentCommandId(false); PushActiveSnapshot(newsnap); }
void CHttpControlSocket::OnConnect() { wxASSERT(GetCurrentCommandId() == cmd_connect); CHttpConnectOpData *pData = static_cast<CHttpConnectOpData *>(m_pCurOpData); if (pData->tls) { if (!m_pTlsSocket) { LogMessage(Status, _("Connection established, initializing TLS...")); delete m_pBackend; m_pTlsSocket = new CTlsSocket(this, m_pSocket, this); m_pBackend = m_pTlsSocket; if (!m_pTlsSocket->Init()) { LogMessage(::Error, _("Failed to initialize TLS.")); DoClose(); return; } const wxString trusted_rootcert = m_pEngine->GetOptions()->GetOption(OPTION_INTERNAL_ROOTCERT); if (trusted_rootcert != _T("") && !m_pTlsSocket->AddTrustedRootCertificate(trusted_rootcert)) { LogMessage(::Error, _("Failed to parse trusted root cert.")); DoClose(); return; } int res = m_pTlsSocket->Handshake(); if (res == FZ_REPLY_ERROR) DoClose(); } else { LogMessage(Status, _("TLS/SSL connection established, sending HTTP request")); ResetOperation(FZ_REPLY_OK); } return; } else { LogMessage(Status, _("Connection established, sending HTTP request")); ResetOperation(FZ_REPLY_OK); } }
/* * UpdateActiveSnapshotCommandId * * Update the current CID of the active snapshot. This can only be applied * to a snapshot that is not referenced elsewhere. */ void UpdateActiveSnapshotCommandId(void) { Assert(ActiveSnapshot != NULL); Assert(ActiveSnapshot->as_snap->active_count == 1); Assert(ActiveSnapshot->as_snap->regd_count == 0); ActiveSnapshot->as_snap->curcid = GetCurrentCommandId(false); #ifdef XCP /* * Set flag so that updated command ID is sent to the datanodes before the * next query. This ensures that the effects of previous statements are * visible to the subsequent statements */ SetSendCommandId(true); #endif }
void CRealControlSocket::OnSend() { if (m_pSendBuffer) { if (!m_nSendBufferLen) { delete [] m_pSendBuffer; m_pSendBuffer = 0; return; } int error; int written = m_pBackend->Write(m_pSendBuffer, m_nSendBufferLen, error); if (written < 0) { if (error != EAGAIN) { LogMessage(MessageType::Error, _("Could not write to socket: %s"), CSocket::GetErrorDescription(error)); if (GetCurrentCommandId() != Command::connect) LogMessage(MessageType::Error, _("Disconnected from server")); DoClose(); } return; } if (written) { SetAlive(); m_pEngine->SetActive(CFileZillaEngine::send); } if (written == m_nSendBufferLen) { m_nSendBufferLen = 0; delete [] m_pSendBuffer; m_pSendBuffer = 0; } else { memmove(m_pSendBuffer, m_pSendBuffer + written, m_nSendBufferLen - written); m_nSendBufferLen -= written; } } }
int CHttpControlSocket::ProcessData(char* p, int len) { int res; enum Command commandId = GetCurrentCommandId(); switch (commandId) { case cmd_transfer: res = FileTransferParseResponse(p, len); break; default: LogMessage(Debug_Warning, _T("No action for parsing data for command %d"), (int)commandId); ResetOperation(FZ_REPLY_INTERNALERROR); res = FZ_REPLY_ERROR; break; } wxASSERT(p || !m_pCurOpData); return res; }
/* * PgPaxosExecutorStart blocks until the table is ready to read. */ static void PgPaxosExecutorStart(QueryDesc *queryDesc, int eflags) { PlannedStmt *plannedStmt = queryDesc->plannedstmt; List *rangeTableList = plannedStmt->rtable; CmdType commandType = queryDesc->operation; if (IsPgPaxosActive() && HasPaxosTable(rangeTableList)) { char *sqlQuery = (char *) queryDesc->sourceText; char *groupId = NULL; bool topLevel = true; /* disallow transactions during paxos commands */ PreventTransactionChain(topLevel, "paxos commands"); groupId = DeterminePaxosGroup(rangeTableList); if (commandType == CMD_INSERT || commandType == CMD_UPDATE || commandType == CMD_DELETE) { PrepareConsistentWrite(groupId, sqlQuery); } else { PrepareConsistentRead(groupId); } queryDesc->snapshot->curcid = GetCurrentCommandId(false); } /* call into the standard executor start, or hook if set */ if (PreviousExecutorStartHook != NULL) { PreviousExecutorStartHook(queryDesc, eflags); } else { standard_ExecutorStart(queryDesc, eflags); } }
/* * simple_table_update - replace a tuple * * This routine may be used to update a tuple when concurrent updates of * the target tuple are not expected (for example, because we have a lock * on the relation associated with the tuple). Any failure is reported * via ereport(). */ void simple_table_update(Relation rel, ItemPointer otid, TupleTableSlot *slot, Snapshot snapshot, bool *update_indexes) { TM_Result result; TM_FailureData tmfd; LockTupleMode lockmode; result = table_update(rel, otid, slot, GetCurrentCommandId(true), snapshot, InvalidSnapshot, true /* wait for commit */ , &tmfd, &lockmode, update_indexes); switch (result) { case TM_SelfModified: /* Tuple was already updated in current command? */ elog(ERROR, "tuple already updated by self"); break; case TM_Ok: /* done successfully */ break; case TM_Updated: elog(ERROR, "tuple concurrently updated"); break; case TM_Deleted: elog(ERROR, "tuple concurrently deleted"); break; default: elog(ERROR, "unrecognized table_update status: %u", result); break; } }
/* * RegisterRelcacheInvalidation * * As above, but register a relcache invalidation event. */ static void RegisterRelcacheInvalidation(Oid dbId, Oid relId) { AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, dbId, relId); /* * Most of the time, relcache invalidation is associated with system * catalog updates, but there are a few cases where it isn't. Quick hack * to ensure that the next CommandCounterIncrement() will think that we * need to do CommandEndInvalidationMessages(). */ (void) GetCurrentCommandId(true); /* * If the relation being invalidated is one of those cached in the * relcache init file, mark that we need to zap that file at commit. */ if (RelationIdIsInInitFile(relId)) transInvalInfo->RelcacheInitFileInval = true; }
static bool matrel_heap_update(Relation relation, ItemPointer otid, HeapTuple tup) { HTSU_Result result; HeapUpdateFailureData hufd; LockTupleMode lockmode; result = heap_update(relation, otid, tup, GetCurrentCommandId(true), InvalidSnapshot, true /* wait for commit */ , &hufd, &lockmode); switch (result) { case HeapTupleSelfUpdated: /* Tuple was already updated in current command? */ elog(ERROR, "tuple already updated by self"); break; case HeapTupleMayBeUpdated: /* done successfully */ break; case HeapTupleUpdated: /* * Tuple updated by a concurrent transaction? The only legal case is if the tuple was deleted * which can happen if the auto-vacuumer deletes the tuple while we were trying to update it. */ if (memcmp(&hufd.ctid, otid, sizeof(ItemPointerData)) == 0) return false; elog(ERROR, "tuple concurrently updated"); break; default: elog(ERROR, "unrecognized heap_update status: %u", result); break; } return true; }
/* * RegisterRelcacheInvalidation * * As above, but register a relcache invalidation event. */ static void RegisterRelcacheInvalidation(Oid dbId, Oid relId) { AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, dbId, relId); /* * Most of the time, relcache invalidation is associated with system * catalog updates, but there are a few cases where it isn't. Quick hack * to ensure that the next CommandCounterIncrement() will think that we * need to do CommandEndInvalidationMessages(). */ (void) GetCurrentCommandId(true); /* * If the relation being invalidated is one of those cached in a relcache * init file, mark that we need to zap that file at commit. For simplicity * invalidations for a specific database always invalidate the shared file * as well. Also zap when we are invalidating whole relcache. */ if (relId == InvalidOid || RelationIdIsInInitFile(relId)) transInvalInfo->RelcacheInitFileInval = true; }
struct GridPointDataListIterator * getExtractGridDataReturnValues(FunctionCallInfo fcinfo) { struct PlaceSpecification ps; Datum placeSpec = PG_GETARG_DATUM(0); extractPlaceSpecification( & ps, & placeSpec ); GEOSGeom location = NULL; if ( ! PG_ARGISNULL(1) ) { bytea * locationRaw = PG_GETARG_BYTEA_P(1); location = GEOSGeomFromWKB_buf((unsigned char *) VARDATA(locationRaw), VARSIZE(locationRaw) - VARHDRSZ); } enum InterpolationType interpolation = (enum InterpolationType) PG_GETARG_INT32(2); FileId dataId = PG_GETARG_INT64(3); TransactionId xid = GetTopTransactionId(); CommandId cid = GetCurrentCommandId(true); // Incremented for each function call in the same transaction // function takes ownership of location parameter struct GridPointDataListIterator * ret = readPoints(& ps, location, interpolation, dataId, xid, cid); return ret; }
/** * @brief Initialize a BufferedWriter */ static void BufferedWriterInit(BufferedWriter *self) { /* * Set defaults to unspecified parameters. */ if (self->base.max_dup_errors < -1) self->base.max_dup_errors = DEFAULT_MAX_DUP_ERRORS; self->base.rel = heap_open(self->base.relid, AccessExclusiveLock); VerifyTarget(self->base.rel, self->base.max_dup_errors); self->base.desc = RelationGetDescr(self->base.rel); SpoolerOpen(&self->spooler, self->base.rel, true, self->base.on_duplicate, self->base.max_dup_errors, self->base.dup_badfile); self->base.context = GetPerTupleMemoryContext(self->spooler.estate); self->bistate = GetBulkInsertState(); self->cid = GetCurrentCommandId(true); self->base.tchecker = CreateTupleChecker(self->base.desc); self->base.tchecker->checker = (CheckerTupleProc) CoercionCheckerTuple; }
/* * simple_table_delete - delete a tuple * * This routine may be used to delete a tuple when concurrent updates of * the target tuple are not expected (for example, because we have a lock * on the relation associated with the tuple). Any failure is reported * via ereport(). */ void simple_table_delete(Relation rel, ItemPointer tid, Snapshot snapshot) { TM_Result result; TM_FailureData tmfd; result = table_delete(rel, tid, GetCurrentCommandId(true), snapshot, InvalidSnapshot, true /* wait for commit */ , &tmfd, false /* changingPart */ ); switch (result) { case TM_SelfModified: /* Tuple was already updated in current command? */ elog(ERROR, "tuple already updated by self"); break; case TM_Ok: /* done successfully */ break; case TM_Updated: elog(ERROR, "tuple concurrently updated"); break; case TM_Deleted: elog(ERROR, "tuple concurrently deleted"); break; default: elog(ERROR, "unrecognized table_delete status: %u", result); break; } }
/* * UpdateActiveSnapshotCommandId * * Update the current CID of the active snapshot. This can only be applied * to a snapshot that is not referenced elsewhere. */ void UpdateActiveSnapshotCommandId(void) { CommandId save_curcid, curcid; Assert(ActiveSnapshot != NULL); Assert(ActiveSnapshot->as_snap->active_count == 1); Assert(ActiveSnapshot->as_snap->regd_count == 0); /* * Don't allow modification of the active snapshot during parallel * operation. We share the snapshot to worker backends at beginning of * parallel operation, so any change to snapshot can lead to * inconsistencies. We have other defenses against * CommandCounterIncrement, but there are a few places that call this * directly, so we put an additional guard here. */ save_curcid = ActiveSnapshot->as_snap->curcid; curcid = GetCurrentCommandId(false); if (IsInParallelMode() && save_curcid != curcid) elog(ERROR, "cannot modify commandid in active snapshot during a parallel operation"); ActiveSnapshot->as_snap->curcid = curcid; }
/* * RegisterRelcacheInvalidation * * As above, but register a relcache invalidation event. */ static void RegisterRelcacheInvalidation(Oid dbId, Oid relId) { AddRelcacheInvalidationMessage(&transInvalInfo->CurrentCmdInvalidMsgs, dbId, relId); /* * Most of the time, relcache invalidation is associated with system * catalog updates, but there are a few cases where it isn't. Quick hack * to ensure that the next CommandCounterIncrement() will think that we * need to do CommandEndInvalidationMessages(). */ (void) GetCurrentCommandId(true); /* * If the relation being invalidated is one of those cached in the local * relcache init file, mark that we need to zap that file at commit. * (Note: perhaps it would be better if this code were a bit more * decoupled from the knowledge that the init file contains exactly those * non-shared rels used in catalog caches.) */ if (OidIsValid(dbId) && RelationSupportsSysCache(relId)) transInvalInfo->RelcacheInitFileInval = true; }
/* ---------- * 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); }
/* * HeapTupleSatisfiesNow * True iff heap tuple is valid "now". * * Here, we consider the effects of: * all committed transactions (as of the current instant) * previous commands of this transaction * * Note we do _not_ include changes made by the current command. This * solves the "Halloween problem" wherein an UPDATE might try to re-update * its own output tuples. * * Note: * Assumes heap tuple is valid. * * The satisfaction of "now" requires the following: * * ((Xmin == my-transaction && inserted by the current transaction * Cmin < my-command && before this command, and * (Xmax is null || the row has not been deleted, or * (Xmax == my-transaction && it was deleted by the current transaction * Cmax >= my-command))) but not before this command, * || or * (Xmin is committed && the row was inserted by a committed transaction, and * (Xmax is null || the row has not been deleted, or * (Xmax == my-transaction && the row is being deleted by this transaction * Cmax >= my-command) || but it's not deleted "yet", or * (Xmax != my-transaction && the row was deleted by another transaction * Xmax is not committed)))) that has not been committed * * mao says 17 march 1993: the tests in this routine are correct; * if you think they're not, you're wrong, and you should think * about it again. i know, it happened to me. we don't need to * check commit time against the start time of this transaction * because 2ph locking protects us from doing the wrong thing. * if you mess around here, you'll break serializability. the only * problem with this code is that it does the wrong thing for system * catalog updates, because the catalogs aren't subject to 2ph, so * the serializability guarantees we provide don't extend to xacts * that do catalog accesses. this is unfortunate, but not critical. */ bool HeapTupleSatisfiesNow(HeapTupleHeader tuple, Snapshot snapshot, Buffer buffer) { if (!(tuple->t_infomask & HEAP_XMIN_COMMITTED)) { if (tuple->t_infomask & HEAP_XMIN_INVALID) return false; if (tuple->t_infomask & HEAP_MOVED_OFF) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (TransactionIdIsCurrentTransactionId(xvac)) return false; if (!TransactionIdIsInProgress(xvac)) { if (TransactionIdDidCommit(xvac)) { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return false; } SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); } } else if (tuple->t_infomask & HEAP_MOVED_IN) { TransactionId xvac = HeapTupleHeaderGetXvac(tuple); if (!TransactionIdIsCurrentTransactionId(xvac)) { if (TransactionIdIsInProgress(xvac)) return false; if (TransactionIdDidCommit(xvac)) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, InvalidTransactionId); else { SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return false; } } } else if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmin(tuple))) { if (HeapTupleHeaderGetCmin(tuple) >= GetCurrentCommandId(false)) return false; /* inserted after scan started */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid */ return true; if (tuple->t_infomask & HEAP_IS_LOCKED) /* not deleter */ return true; Assert(!(tuple->t_infomask & HEAP_XMAX_IS_MULTI)); if (!TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple))) { /* deleting subtransaction must have aborted */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return true; } if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false)) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } else if (TransactionIdIsInProgress(HeapTupleHeaderGetXmin(tuple))) return false; else if (TransactionIdDidCommit(HeapTupleHeaderGetXmin(tuple))) SetHintBits(tuple, buffer, HEAP_XMIN_COMMITTED, HeapTupleHeaderGetXmin(tuple)); else { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMIN_INVALID, InvalidTransactionId); return false; } } /* by here, the inserting transaction has committed */ if (tuple->t_infomask & HEAP_XMAX_INVALID) /* xid invalid or aborted */ return true; if (tuple->t_infomask & HEAP_XMAX_COMMITTED) { if (tuple->t_infomask & HEAP_IS_LOCKED) return true; return false; } if (tuple->t_infomask & HEAP_XMAX_IS_MULTI) { /* MultiXacts are currently only allowed to lock tuples */ Assert(tuple->t_infomask & HEAP_IS_LOCKED); return true; } if (TransactionIdIsCurrentTransactionId(HeapTupleHeaderGetXmax(tuple))) { if (tuple->t_infomask & HEAP_IS_LOCKED) return true; if (HeapTupleHeaderGetCmax(tuple) >= GetCurrentCommandId(false)) return true; /* deleted after scan started */ else return false; /* deleted before scan started */ } if (TransactionIdIsInProgress(HeapTupleHeaderGetXmax(tuple))) return true; if (!TransactionIdDidCommit(HeapTupleHeaderGetXmax(tuple))) { /* it must have aborted or crashed */ SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return true; } /* xmax transaction committed */ if (tuple->t_infomask & HEAP_IS_LOCKED) { SetHintBits(tuple, buffer, HEAP_XMAX_INVALID, InvalidTransactionId); return true; } SetHintBits(tuple, buffer, HEAP_XMAX_COMMITTED, HeapTupleHeaderGetXmax(tuple)); return false; }
/* * intorel_startup --- executor startup */ static void intorel_startup(DestReceiver *self, int operation, TupleDesc typeinfo) { DR_intorel *myState = (DR_intorel *) self; IntoClause *into = myState->into; bool is_matview; char relkind; CreateStmt *create; Oid intoRelationId; Relation intoRelationDesc; RangeTblEntry *rte; Datum toast_options; ListCell *lc; int attnum; static char *validnsps[] = HEAP_RELOPT_NAMESPACES; Assert(into != NULL); /* else somebody forgot to set it */ /* This code supports both CREATE TABLE AS and CREATE MATERIALIZED VIEW */ is_matview = (into->viewQuery != NULL); relkind = is_matview ? RELKIND_MATVIEW : RELKIND_RELATION; /* * Create the target relation by faking up a CREATE TABLE parsetree and * passing it to DefineRelation. */ create = makeNode(CreateStmt); create->relation = into->rel; create->tableElts = NIL; /* will fill below */ create->inhRelations = NIL; create->ofTypename = NULL; create->constraints = NIL; create->options = into->options; create->oncommit = into->onCommit; create->tablespacename = into->tableSpaceName; create->if_not_exists = false; /* * Build column definitions using "pre-cooked" type and collation info. If * a column name list was specified in CREATE TABLE AS, override the * column names derived from the query. (Too few column names are OK, too * many are not.) */ lc = list_head(into->colNames); for (attnum = 0; attnum < typeinfo->natts; attnum++) { Form_pg_attribute attribute = typeinfo->attrs[attnum]; ColumnDef *col = makeNode(ColumnDef); TypeName *coltype = makeNode(TypeName); if (lc) { col->colname = strVal(lfirst(lc)); lc = lnext(lc); } else col->colname = NameStr(attribute->attname); col->typeName = coltype; col->inhcount = 0; col->is_local = true; col->is_not_null = false; col->is_from_type = false; col->storage = 0; col->raw_default = NULL; col->cooked_default = NULL; col->collClause = NULL; col->collOid = attribute->attcollation; col->constraints = NIL; col->fdwoptions = NIL; coltype->names = NIL; coltype->typeOid = attribute->atttypid; coltype->setof = false; coltype->pct_type = false; coltype->typmods = NIL; coltype->typemod = attribute->atttypmod; coltype->arrayBounds = NIL; coltype->location = -1; /* * It's possible that the column is of a collatable type but the * collation could not be resolved, so double-check. (We must check * this here because DefineRelation would adopt the type's default * collation rather than complaining.) */ if (!OidIsValid(col->collOid) && type_is_collatable(coltype->typeOid)) ereport(ERROR, (errcode(ERRCODE_INDETERMINATE_COLLATION), errmsg("no collation was derived for column \"%s\" with collatable type %s", col->colname, format_type_be(coltype->typeOid)), errhint("Use the COLLATE clause to set the collation explicitly."))); create->tableElts = lappend(create->tableElts, col); } if (lc != NULL) ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("too many column names were specified"))); /* * Actually create the target table */ intoRelationId = DefineRelation(create, relkind, InvalidOid); /* * If necessary, create a TOAST table for the target table. Note that * AlterTableCreateToastTable ends with CommandCounterIncrement(), so that * the TOAST table will be visible for insertion. */ CommandCounterIncrement(); /* parse and validate reloptions for the toast table */ toast_options = transformRelOptions((Datum) 0, create->options, "toast", validnsps, true, false); (void) heap_reloptions(RELKIND_TOASTVALUE, toast_options, true); AlterTableCreateToastTable(intoRelationId, toast_options); /* Create the "view" part of a materialized view. */ if (is_matview) { /* StoreViewQuery scribbles on tree, so make a copy */ Query *query = (Query *) copyObject(into->viewQuery); StoreViewQuery(intoRelationId, query, false); CommandCounterIncrement(); } /* * Finally we can open the target table */ intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock); /* * Check INSERT permission on the constructed table. * * XXX: It would arguably make sense to skip this check if into->skipData * is true. */ rte = makeNode(RangeTblEntry); rte->rtekind = RTE_RELATION; rte->relid = intoRelationId; rte->relkind = relkind; rte->requiredPerms = ACL_INSERT; for (attnum = 1; attnum <= intoRelationDesc->rd_att->natts; attnum++) rte->modifiedCols = bms_add_member(rte->modifiedCols, attnum - FirstLowInvalidHeapAttributeNumber); ExecCheckRTPerms(list_make1(rte), true); /* * Tentatively mark the target as populated, if it's a matview and we're * going to fill it; otherwise, no change needed. */ if (is_matview && !into->skipData) SetMatViewPopulatedState(intoRelationDesc, true); /* * Fill private fields of myState for use by later routines */ myState->rel = intoRelationDesc; myState->output_cid = GetCurrentCommandId(true); /* * We can skip WAL-logging the insertions, unless PITR or streaming * replication is in use. We can skip the FSM in any case. */ myState->hi_options = HEAP_INSERT_SKIP_FSM | (XLogIsNeeded() ? 0 : HEAP_INSERT_SKIP_WAL); myState->bistate = GetBulkInsertState(); /* Not using WAL requires smgr_targblock be initially invalid */ Assert(RelationGetTargetBlock(intoRelationDesc) == InvalidBlockNumber); }