void PLy_spi_subtransaction_abort(MemoryContext oldcontext, ResourceOwner oldowner) { ErrorData *edata; PLyExceptionEntry *entry; PyObject *exc; /* Save error info */ MemoryContextSwitchTo(oldcontext); edata = CopyErrorData(); FlushErrorState(); /* Abort the inner transaction */ RollbackAndReleaseCurrentSubTransaction(); MemoryContextSwitchTo(oldcontext); CurrentResourceOwner = oldowner; /* * If AtEOSubXact_SPI() popped any SPI context of the subxact, it will have * left us in a disconnected state. We need this hack to return to * connected state. */ SPI_restore_connection(); /* Look up the correct exception */ entry = hash_search(PLy_spi_exceptions, &(edata->sqlerrcode), HASH_FIND, NULL); /* We really should find it, but just in case have a fallback */ Assert(entry != NULL); exc = entry ? entry->exc : PLy_exc_spi_error; /* Make Python raise the exception */ PLy_spi_exception_set(exc, edata); FreeErrorData(edata); }
static void luaP_throwsqlerr (lua_State *L, ErrorData *ed) { SPI_restore_connection(); lua_pushstring(L, ed->message); FreeErrorData(ed); lua_pushlightuserdata(L, (void *)PLLUA_TXNABORT); lua_pushvalue(L, -2); lua_rawset(L, LUA_REGISTRYINDEX); lua_error(L); }
/* * Class: org_postgresql_pljava_internal_ErrorData * Method: _free * Signature: (J)V */ JNIEXPORT void JNICALL Java_org_postgresql_pljava_internal_ErrorData__1free(JNIEnv* env, jobject _this, jlong pointer) { BEGIN_NATIVE_NO_ERRCHECK Ptr2Long p2l; p2l.longVal = pointer; FreeErrorData(p2l.ptrVal); END_NATIVE }
static int geterrcode(void) { /* switch context to work around Assert() in CopyErrorData() */ MemoryContext ctx = MemoryContextSwitchTo(TopMemoryContext); ErrorData *edata = CopyErrorData(); int code = edata->sqlerrcode; FreeErrorData(edata); MemoryContextSwitchTo(ctx); return code; }
int FNC::SetErrorData( const char *errors, int errorsLength, int wait_ms ) { Synchronized sync(m_dataMutex); if (errors && errorsLength) { // discard any unsent data FreeErrorData(); // copy new data to local storage until we can send it to DS m_userErrMsg = new char[errorsLength]; memcpy(m_userErrMsg, errors, errorsLength); m_userErrMsgLength = errorsLength; } return OK; }
/* * A function having everything to do with logging, which ought to be factored * out one day to make a start on the Thoughts-on-logging wiki ideas. */ static void reLogWithChangedLevel(int level) { ErrorData *edata = CopyErrorData(); int sqlstate = edata->sqlerrcode; int category = ERRCODE_TO_CATEGORY(sqlstate); FlushErrorState(); if ( WARNING > level ) { if ( ERRCODE_SUCCESSFUL_COMPLETION != category ) sqlstate = ERRCODE_SUCCESSFUL_COMPLETION; } else if ( WARNING == level ) { if ( ERRCODE_WARNING != category && ERRCODE_NO_DATA != category ) sqlstate = ERRCODE_WARNING; } else if ( ERRCODE_WARNING == category || ERRCODE_NO_DATA == category || ERRCODE_SUCCESSFUL_COMPLETION == category ) sqlstate = ERRCODE_INTERNAL_ERROR; #if PG_VERSION_NUM >= 90500 edata->elevel = level; edata->sqlerrcode = sqlstate; PG_TRY(); { ThrowErrorData(edata); } PG_CATCH(); { FreeErrorData(edata); /* otherwise this wouldn't happen in ERROR case */ PG_RE_THROW(); } PG_END_TRY(); FreeErrorData(edata); #else if (!errstart(level, edata->filename, edata->lineno, edata->funcname, NULL)) { FreeErrorData(edata); return; } errcode(sqlstate); if (edata->message) errmsg("%s", edata->message); if (edata->detail) errdetail("%s", edata->detail); if (edata->detail_log) errdetail_log("%s", edata->detail_log); if (edata->hint) errhint("%s", edata->hint); if (edata->context) errcontext("%s", edata->context); /* this may need to be trimmed */ #if PG_VERSION_NUM >= 90300 if (edata->schema_name) err_generic_string(PG_DIAG_SCHEMA_NAME, edata->schema_name); if (edata->table_name) err_generic_string(PG_DIAG_TABLE_NAME, edata->table_name); if (edata->column_name) err_generic_string(PG_DIAG_COLUMN_NAME, edata->column_name); if (edata->datatype_name) err_generic_string(PG_DIAG_DATATYPE_NAME, edata->datatype_name); if (edata->constraint_name) err_generic_string(PG_DIAG_CONSTRAINT_NAME, edata->constraint_name); #endif if (edata->internalquery) internalerrquery(edata->internalquery); FreeErrorData(edata); errfinish(0); #endif }
/** * @brief Read the next tuple from parser. * @param rd [in/out] reader * @return type */ HeapTuple ReaderNext(Reader *rd) { HeapTuple tuple; MemoryContext ccxt; bool eof; Parser *parser = rd->parser; ccxt = CurrentMemoryContext; eof = false; do { tuple = NULL; parser->parsing_field = -1; PG_TRY(); { tuple = ParserRead(parser, &rd->checker); if (tuple == NULL) eof = true; else { tuple = CheckerTuple(&rd->checker, tuple, &parser->parsing_field); CheckerConstraints(&rd->checker, tuple, &parser->parsing_field); } } PG_CATCH(); { ErrorData *errdata; MemoryContext ecxt; char *message; StringInfoData buf; if (parser->parsing_field < 0) PG_RE_THROW(); /* should not ignore */ ecxt = MemoryContextSwitchTo(ccxt); errdata = CopyErrorData(); /* We cannot ignore query aborts. */ switch (errdata->sqlerrcode) { case ERRCODE_ADMIN_SHUTDOWN: case ERRCODE_QUERY_CANCELED: MemoryContextSwitchTo(ecxt); PG_RE_THROW(); break; } /* Absorb parse errors. */ rd->parse_errors++; if (errdata->message) message = pstrdup(errdata->message); else message = "<no error message>"; FlushErrorState(); FreeErrorData(errdata); initStringInfo(&buf); appendStringInfo(&buf, "Parse error Record " int64_FMT ": Input Record " int64_FMT ": Rejected", rd->parse_errors, parser->count); if (parser->parsing_field > 0) appendStringInfo(&buf, " - column %d", parser->parsing_field); appendStringInfo(&buf, ". %s\n", message); LoggerLog(WARNING, buf.data); /* Terminate if PARSE_ERRORS has been reached. */ if (rd->parse_errors > rd->max_parse_errors) { eof = true; LoggerLog(WARNING, "Maximum parse error count exceeded - " int64_FMT " error(s) found in input file\n", rd->parse_errors); } /* output parse bad file. */ if (rd->parse_fp == NULL) if ((rd->parse_fp = AllocateFile(rd->parse_badfile, "w")) == NULL) ereport(ERROR, (errcode_for_file_access(), errmsg("could not open parse bad file \"%s\": %m", rd->parse_badfile))); ParserDumpRecord(parser, rd->parse_fp, rd->parse_badfile); MemoryContextReset(ccxt); // Without the below line, the regression tests shows the different result on debug-build mode. tuple = NULL; } PG_END_TRY(); } while (!eof && !tuple); BULKLOAD_PROFILE(&prof_reader_parser); return tuple; }
static PyObject * PLy_output(volatile int level, PyObject *self, PyObject *args, PyObject *kw) { int sqlstate = 0; char *volatile sqlstatestr = NULL; char *volatile message = NULL; char *volatile detail = NULL; char *volatile hint = NULL; char *volatile column_name = NULL; char *volatile constraint_name = NULL; char *volatile datatype_name = NULL; char *volatile table_name = NULL; char *volatile schema_name = NULL; volatile MemoryContext oldcontext; PyObject *key, *value; PyObject *volatile so; Py_ssize_t pos = 0; if (PyTuple_Size(args) == 1) { /* * Treat single argument specially to avoid undesirable ('tuple',) * decoration. */ PyObject *o; if (!PyArg_UnpackTuple(args, "plpy.elog", 1, 1, &o)) PLy_elog(ERROR, "could not unpack arguments in plpy.elog"); so = PyObject_Str(o); } else so = PyObject_Str(args); if (so == NULL || ((message = PyString_AsString(so)) == NULL)) { level = ERROR; message = dgettext(TEXTDOMAIN, "could not parse error message in plpy.elog"); } message = pstrdup(message); Py_XDECREF(so); if (kw != NULL) { while (PyDict_Next(kw, &pos, &key, &value)) { char *keyword = PyString_AsString(key); if (strcmp(keyword, "message") == 0) { /* the message should not be overwriten */ if (PyTuple_Size(args) != 0) { PLy_exception_set(PyExc_TypeError, "Argument 'message' given by name and position"); return NULL; } if (message) pfree(message); message = object_to_string(value); } else if (strcmp(keyword, "detail") == 0) detail = object_to_string(value); else if (strcmp(keyword, "hint") == 0) hint = object_to_string(value); else if (strcmp(keyword, "sqlstate") == 0) sqlstatestr = object_to_string(value); else if (strcmp(keyword, "schema_name") == 0) schema_name = object_to_string(value); else if (strcmp(keyword, "table_name") == 0) table_name = object_to_string(value); else if (strcmp(keyword, "column_name") == 0) column_name = object_to_string(value); else if (strcmp(keyword, "datatype_name") == 0) datatype_name = object_to_string(value); else if (strcmp(keyword, "constraint_name") == 0) constraint_name = object_to_string(value); else { PLy_exception_set(PyExc_TypeError, "'%s' is an invalid keyword argument for this function", keyword); return NULL; } } } if (sqlstatestr != NULL) { if (strlen(sqlstatestr) != 5) { PLy_exception_set(PyExc_ValueError, "invalid SQLSTATE code"); return NULL; } if (strspn(sqlstatestr, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ") != 5) { PLy_exception_set(PyExc_ValueError, "invalid SQLSTATE code"); return NULL; } sqlstate = MAKE_SQLSTATE(sqlstatestr[0], sqlstatestr[1], sqlstatestr[2], sqlstatestr[3], sqlstatestr[4]); } oldcontext = CurrentMemoryContext; PG_TRY(); { if (message != NULL) pg_verifymbstr(message, strlen(message), false); if (detail != NULL) pg_verifymbstr(detail, strlen(detail), false); if (hint != NULL) pg_verifymbstr(hint, strlen(hint), false); if (schema_name != NULL) pg_verifymbstr(schema_name, strlen(schema_name), false); if (table_name != NULL) pg_verifymbstr(table_name, strlen(table_name), false); if (column_name != NULL) pg_verifymbstr(column_name, strlen(column_name), false); if (datatype_name != NULL) pg_verifymbstr(datatype_name, strlen(datatype_name), false); if (constraint_name != NULL) pg_verifymbstr(constraint_name, strlen(constraint_name), false); ereport(level, ((sqlstate != 0) ? errcode(sqlstate) : 0, (message != NULL) ? errmsg_internal("%s", message) : 0, (detail != NULL) ? errdetail_internal("%s", detail) : 0, (hint != NULL) ? errhint("%s", hint) : 0, (column_name != NULL) ? err_generic_string(PG_DIAG_COLUMN_NAME, column_name) : 0, (constraint_name != NULL) ? err_generic_string(PG_DIAG_CONSTRAINT_NAME, constraint_name) : 0, (datatype_name != NULL) ? err_generic_string(PG_DIAG_DATATYPE_NAME, datatype_name) : 0, (table_name != NULL) ? err_generic_string(PG_DIAG_TABLE_NAME, table_name) : 0, (schema_name != NULL) ? err_generic_string(PG_DIAG_SCHEMA_NAME, schema_name) : 0)); } PG_CATCH(); { ErrorData *edata; MemoryContextSwitchTo(oldcontext); edata = CopyErrorData(); FlushErrorState(); PLy_exception_set_with_details(PLy_exc_error, edata); FreeErrorData(edata); return NULL; } PG_END_TRY(); /* * return a legal object so the interpreter will continue on its merry way */ Py_INCREF(Py_None); return Py_None; }
Datum pgsynck(PG_FUNCTION_ARGS) { /* List *raw_parsetree_list = NULL; */ char *query_string = NULL; char *oneq = NULL; char *q; ErrorData *edata = NULL; MemoryContext oldcontext = CurrentMemoryContext; MemoryContext per_query_ctx; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; TupleDesc tupdesc; Tuplestorestate *tupstore; /* check to see if caller supports us returning a tuplestore */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("set-valued function called in context that cannot accept a set"))); if (!(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("materialize mode required, but it is not " \ "allowed in this context"))); /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; oldcontext = MemoryContextSwitchTo(per_query_ctx); tupstore = tuplestore_begin_heap(true, false, work_mem); rsinfo->returnMode = SFRM_Materialize; rsinfo->setResult = tupstore; rsinfo->setDesc = tupdesc; MemoryContextSwitchTo(oldcontext); q = query_string = text_to_cstring(PG_GETARG_TEXT_PP(0)); oneq = get_one_query(&q); while (oneq != NULL) { int j = 0; Datum values[PGSYNCK_COLS]; bool nulls[PGSYNCK_COLS]; memset(values, 0, sizeof(values)); memset(nulls, 0, sizeof(nulls)); /* sql */ values[j++] = CStringGetTextDatum(oneq); PG_TRY(); { raw_parser(oneq); /* cursorpos */ values[j++] = Int32GetDatum(0); /* sqlerrcode */ values[j++] = Int32GetDatum(0); /* message - primary error message */ values[j++] = CStringGetTextDatum(""); /* hint - hint message */ values[j++] = CStringGetTextDatum(""); tuplestore_putvalues(tupstore, tupdesc, values, nulls); } PG_CATCH(); { /* Save error info */ MemoryContextSwitchTo(oldcontext); edata = CopyErrorData(); FlushErrorState(); /* cursorpos - cursor index into query string */ values[j++] = Int32GetDatum(edata->cursorpos); /* sqlerrcode - encoded ERRSTATE */ values[j++] = Int32GetDatum(edata->sqlerrcode); /* message - primary error message */ values[j++] = CStringGetTextDatum(edata->message ? edata->message:""); /* hint - hint message */ values[j++] = CStringGetTextDatum(edata->hint ? edata->hint:""); tuplestore_putvalues(tupstore, tupdesc, values, nulls); FreeErrorData(edata); } PG_END_TRY(); oneq = get_one_query(&q); } /* clean up and return the tuplestore */ tuplestore_donestoring(tupstore); return (Datum) 0; }
int FNC::Send() { Synchronized sync(m_dataMutex); memset(&m_sendPkt, 0, sizeof m_sendPkt); // send our current control mode back to DS // keep the same bit ordering sent from the DS m_sendPkt.control = m_recvPkt.ctrl.control; // battery voltage - BCD scaled integer int vbat = (int)(m_battery * 100.0); m_sendPkt.battery[0] = (((vbat / 1000) % 10) << 4) | ((vbat / 100) % 10); m_sendPkt.battery[1] = (((vbat / 10) % 10) << 4) | (vbat % 10); // 8 bits of "digital outputs" displayed on DS m_sendPkt.dsDigitalOut = m_dsDigitalOut; // copy team ID from DS control packet m_sendPkt.teamID = htons(m_recvData.teamID); // fake the cRIO MAC address - does the DS care about this? memcpy(m_sendPkt.macAddr, fakeMAC, 6); // fake the FRC_NetworkCommunication version strncpy(m_sendPkt.versionData, commVersion, sizeof m_sendPkt.versionData); // robot operating mode m_sendPkt.mode = htons(m_mode); // copy last received packet number from DS control packet m_sendPkt.packetIndex = htons(m_recvData.packetIndex); // dashboard status update number m_sendPkt.updateNumber = m_updateNumber; // dashboard data...include as much as will fit in the allowed space // high-priority data length (4 bytes) // high-priority data bytes (variable-length) // error message length (4 bytes) // error message string (variable-length) // low-priority data length (4 bytes) // low-priority data bytes (variable-length) unsigned int udlen = 0; const unsigned int udMaxLen = sizeof m_sendPkt.userData; if (udlen + sizeof (uint32_t) + m_userDataHighLength <= udMaxLen) { uint32_t udhl = htonl(m_userDataHighLength); memcpy(&m_sendPkt.userData[udlen], &udhl, sizeof udhl); udlen += sizeof udhl; if (m_userDataHigh) { memcpy(&m_sendPkt.userData[udlen], m_userDataHigh, m_userDataHighLength); udlen += m_userDataHighLength; // now that the message has been sent, free the local copy FreeUserDataHigh(); } } if (udlen + sizeof (uint32_t) + m_userErrMsgLength <= udMaxLen) { uint32_t erl = htonl(m_userErrMsgLength); memcpy(&m_sendPkt.userData[udlen], &erl, sizeof erl); udlen += sizeof erl; if (m_userErrMsg) { memcpy(&m_sendPkt.userData[udlen], m_userErrMsg, m_userErrMsgLength); udlen += m_userErrMsgLength; // now that the message has been sent, free the local copy FreeErrorData(); } } if (udlen + sizeof (uint32_t) + m_userDataLowLength <= udMaxLen) { uint32_t udll = htonl(m_userDataLowLength); memcpy(&m_sendPkt.userData[udlen], &udll, sizeof udll); udlen += sizeof udll; if (m_userDataLow) { memcpy(&m_sendPkt.userData[udlen], m_userDataLow, m_userDataLowLength); udlen += m_userDataLowLength; // now that the message has been sent, free the local copy FreeUserDataLow(); } } #if 0 // this is a hack // the real robot code updates this data once/second // and it's not clear how the numbers are generated // (or why it needs to be 40 bytes long!) clock_gettime(CLOCK_REALTIME, (timespec *)m_sendPkt.sysstat); #endif // DS Enhanced I/O configuration if (m_eioConfig) { memcpy(m_sendPkt.eioConfig, m_eioConfig, m_eioConfigLength); if (m_eioConfigLength >= 26 && m_sendPkt.eioConfig[1] == kFRC_NetworkCommunication_DynamicType_DSEnhancedIO_Output) { SwapDSEIOOutput((output_t *)&m_sendPkt.eioConfig[2]); } FreeEIOConfig(); } // calculate CRC on the first 1024 bytes uint32_t crc = crc32(0, Z_NULL, 0); crc = crc32(crc, (uint8_t *)&m_sendPkt, 1024); m_sendPkt.crc = htonl(crc); m_sendPktLength = 1024; if (m_lcdData) { if (m_lcdDataLength <= sizeof m_sendPkt.lcdData) { memcpy(m_sendPkt.lcdData, m_lcdData, m_lcdDataLength); m_sendPktLength += m_lcdDataLength; } FreeLCDData(); } m_toAddr.sin_family = AF_INET; m_toAddr.sin_addr.s_addr = m_fromAddr.sin_addr.s_addr; m_toAddr.sin_port = htons(DS_REPLY_PORT); int n = sendto(m_sendSocket, (char *)&m_sendPkt, m_sendPktLength, 0, (struct sockaddr *)&m_toAddr, sizeof m_toAddr); if (n == -1) { perror("FRC_NetworkCommunication::Recv::sendto"); return ERROR; } m_pcap->write_record(&m_sendAddr, &m_toAddr, (char *)&m_sendPkt, n); return OK; }
/** * @brief Entry point of the user-defined function for pg_bulkload. * @return Returns number of loaded tuples. If the case of errors, -1 will be * returned. */ Datum pg_bulkload(PG_FUNCTION_ARGS) { Reader *rd = NULL; Writer *wt = NULL; Datum options; MemoryContext ctx; MemoryContext ccxt; PGRUsage ru0; PGRUsage ru1; int64 count; int64 parse_errors; int64 skip; WriterResult ret; char *start; char *end; float8 system; float8 user; float8 duration; TupleDesc tupdesc; Datum values[PG_BULKLOAD_COLS]; bool nulls[PG_BULKLOAD_COLS]; HeapTuple result; /* Build a tuple descriptor for our result type */ if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) elog(ERROR, "return type must be a row type"); BULKLOAD_PROFILE_PUSH(); pg_rusage_init(&ru0); /* must be the super user */ if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to use pg_bulkload"))); options = PG_GETARG_DATUM(0); ccxt = CurrentMemoryContext; /* * STEP 1: Initialization */ /* parse options and create reader and writer */ ParseOptions(options, &rd, &wt, ru0.tv.tv_sec); /* initialize reader */ ReaderInit(rd); /* * We need to split PG_TRY block because gcc optimizes if-branches with * longjmp codes too much. Local variables initialized in either branch * cannot be handled another branch. */ PG_TRY(); { /* truncate heap */ if (wt->truncate) TruncateTable(wt->relid); /* initialize writer */ WriterInit(wt); /* initialize checker */ CheckerInit(&rd->checker, wt->rel, wt->tchecker); /* initialize parser */ ParserInit(rd->parser, &rd->checker, rd->infile, wt->desc, wt->multi_process, PG_GET_COLLATION()); } PG_CATCH(); { if (rd) ReaderClose(rd, true); if (wt) WriterClose(wt, true); PG_RE_THROW(); } PG_END_TRY(); /* No throwable codes here! */ PG_TRY(); { /* create logger */ CreateLogger(rd->logfile, wt->verbose, rd->infile[0] == ':'); start = timeval_to_cstring(ru0.tv); LoggerLog(INFO, "\npg_bulkload %s on %s\n\n", PG_BULKLOAD_VERSION, start); ReaderDumpParams(rd); WriterDumpParams(wt); LoggerLog(INFO, "\n"); BULKLOAD_PROFILE(&prof_init); /* * STEP 2: Build heap */ /* Switch into its memory context */ Assert(wt->context); ctx = MemoryContextSwitchTo(wt->context); /* Loop for each input file record. */ while (wt->count < rd->limit) { HeapTuple tuple; CHECK_FOR_INTERRUPTS(); /* read tuple */ BULKLOAD_PROFILE_PUSH(); tuple = ReaderNext(rd); BULKLOAD_PROFILE_POP(); BULKLOAD_PROFILE(&prof_reader); if (tuple == NULL) break; /* write tuple */ BULKLOAD_PROFILE_PUSH(); WriterInsert(wt, tuple); wt->count += 1; BULKLOAD_PROFILE_POP(); BULKLOAD_PROFILE(&prof_writer); MemoryContextReset(wt->context); BULKLOAD_PROFILE(&prof_reset); } MemoryContextSwitchTo(ctx); /* * STEP 3: Finalize heap and merge indexes */ count = wt->count; parse_errors = rd->parse_errors; /* * close writer first and reader second because shmem_exit callback * is managed by a simple stack. */ ret = WriterClose(wt, false); wt = NULL; skip = ReaderClose(rd, false); rd = NULL; } PG_CATCH(); { ErrorData *errdata; MemoryContext ecxt; ecxt = MemoryContextSwitchTo(ccxt); errdata = CopyErrorData(); LoggerLog(INFO, "%s\n", errdata->message); FreeErrorData(errdata); /* close writer first, and reader second */ if (wt) WriterClose(wt, true); if (rd) ReaderClose(rd, true); MemoryContextSwitchTo(ecxt); PG_RE_THROW(); } PG_END_TRY(); count -= ret.num_dup_new; LoggerLog(INFO, "\n" " " int64_FMT " Rows skipped.\n" " " int64_FMT " Rows successfully loaded.\n" " " int64_FMT " Rows not loaded due to parse errors.\n" " " int64_FMT " Rows not loaded due to duplicate errors.\n" " " int64_FMT " Rows replaced with new rows.\n\n", skip, count, parse_errors, ret.num_dup_new, ret.num_dup_old); pg_rusage_init(&ru1); system = diffTime(ru1.ru.ru_stime, ru0.ru.ru_stime); user = diffTime(ru1.ru.ru_utime, ru0.ru.ru_utime); duration = diffTime(ru1.tv, ru0.tv); end = timeval_to_cstring(ru1.tv); memset(nulls, 0, sizeof(nulls)); values[0] = Int64GetDatum(skip); values[1] = Int64GetDatum(count); values[2] = Int64GetDatum(parse_errors); values[3] = Int64GetDatum(ret.num_dup_new); values[4] = Int64GetDatum(ret.num_dup_old); values[5] = Float8GetDatumFast(system); values[6] = Float8GetDatumFast(user); values[7] = Float8GetDatumFast(duration); LoggerLog(INFO, "Run began on %s\n" "Run ended on %s\n\n" "CPU %.2fs/%.2fu sec elapsed %.2f sec\n", start, end, system, user, duration); LoggerClose(); result = heap_form_tuple(tupdesc, values, nulls); BULKLOAD_PROFILE(&prof_fini); BULKLOAD_PROFILE_POP(); BULKLOAD_PROFILE_PRINT(); PG_RETURN_DATUM(HeapTupleGetDatum(result)); }