/* * PerformCursorOpen * Execute SQL DECLARE CURSOR command. */ void PerformCursorOpen(DeclareCursorStmt *cstmt, ParamListInfo params, const char *queryString, bool isTopLevel) { Query *query = castNode(Query, cstmt->query); List *rewritten; PlannedStmt *plan; Portal portal; MemoryContext oldContext; /* * Disallow empty-string cursor name (conflicts with protocol-level * unnamed portal). */ if (!cstmt->portalname || cstmt->portalname[0] == '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_CURSOR_NAME), errmsg("invalid cursor name: must not be empty"))); /* * If this is a non-holdable cursor, we require that this statement has * been executed inside a transaction block (or else, it would have no * user-visible effect). */ if (!(cstmt->options & CURSOR_OPT_HOLD)) RequireTransactionChain(isTopLevel, "DECLARE CURSOR"); /* * Parse analysis was done already, but we still have to run the rule * rewriter. We do not do AcquireRewriteLocks: we assume the query either * came straight from the parser, or suitable locks were acquired by * plancache.c. * * Because the rewriter and planner tend to scribble on the input, we make * a preliminary copy of the source querytree. This prevents problems in * the case that the DECLARE CURSOR is in a portal or plpgsql function and * is executed repeatedly. (See also the same hack in EXPLAIN and * PREPARE.) XXX FIXME someday. */ rewritten = QueryRewrite((Query *) copyObject(query)); /* SELECT should never rewrite to more or less than one query */ if (list_length(rewritten) != 1) elog(ERROR, "non-SELECT statement in DECLARE CURSOR"); query = castNode(Query, linitial(rewritten)); if (query->commandType != CMD_SELECT) elog(ERROR, "non-SELECT statement in DECLARE CURSOR"); /* Plan the query, applying the specified options */ plan = pg_plan_query(query, cstmt->options, params); /* * Create a portal and copy the plan and queryString into its memory. */ portal = CreatePortal(cstmt->portalname, false, false); oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); plan = copyObject(plan); queryString = pstrdup(queryString); PortalDefineQuery(portal, NULL, queryString, "SELECT", /* cursor's query is always a SELECT */ list_make1(plan), NULL); /*---------- * Also copy the outer portal's parameter list into the inner portal's * memory context. We want to pass down the parameter values in case we * had a command like * DECLARE c CURSOR FOR SELECT ... WHERE foo = $1 * This will have been parsed using the outer parameter set and the * parameter value needs to be preserved for use when the cursor is * executed. *---------- */ params = copyParamList(params); MemoryContextSwitchTo(oldContext); /* * Set up options for portal. * * If the user didn't specify a SCROLL type, allow or disallow scrolling * based on whether it would require any additional runtime overhead to do * so. Also, we disallow scrolling for FOR UPDATE cursors. */ portal->cursorOptions = cstmt->options; if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL))) { if (plan->rowMarks == NIL && ExecSupportsBackwardScan(plan->planTree)) portal->cursorOptions |= CURSOR_OPT_SCROLL; else portal->cursorOptions |= CURSOR_OPT_NO_SCROLL; } /* * Start execution, inserting parameters if any. */ PortalStart(portal, params, 0, GetActiveSnapshot()); Assert(portal->strategy == PORTAL_ONE_SELECT); /* * We're done; the query won't actually be run until PerformPortalFetch is * called. */ }
void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &tokenizer) { (void)tokenlist; (void)tokenizer; #ifdef HAVE_RULES // Are there rules to execute? bool isrule = false; for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { if (it->tokenlist == tokenlist) isrule = true; } // There is no rule to execute if (isrule == false) return; // Write all tokens in a string that can be parsed by pcre std::ostringstream ostr; for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) ostr << " " << tok->str(); const std::string str(ostr.str()); for (std::list<Settings::Rule>::const_iterator it = _settings.rules.begin(); it != _settings.rules.end(); ++it) { const Settings::Rule &rule = *it; if (rule.pattern.empty() || rule.id.empty() || rule.severity.empty() || rule.tokenlist != tokenlist) continue; const char *error = nullptr; int erroffset = 0; pcre *re = pcre_compile(rule.pattern.c_str(),0,&error,&erroffset,nullptr); if (!re) { if (error) { ErrorLogger::ErrorMessage errmsg(std::list<ErrorLogger::ErrorMessage::FileLocation>(), Severity::error, error, "pcre_compile", false); reportErr(errmsg); } continue; } int pos = 0; int ovector[30]; while (pos < (int)str.size() && 0 <= pcre_exec(re, nullptr, str.c_str(), (int)str.size(), pos, 0, ovector, 30)) { unsigned int pos1 = (unsigned int)ovector[0]; unsigned int pos2 = (unsigned int)ovector[1]; // jump to the end of the match for the next pcre_exec pos = (int)pos2; // determine location.. ErrorLogger::ErrorMessage::FileLocation loc; loc.setfile(tokenizer.list.getSourceFilePath()); loc.line = 0; std::size_t len = 0; for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) { len = len + 1U + tok->str().size(); if (len > pos1) { loc.setfile(tokenizer.list.getFiles().at(tok->fileIndex())); loc.line = tok->linenr(); break; } } const std::list<ErrorLogger::ErrorMessage::FileLocation> callStack(1, loc); // Create error message std::string summary; if (rule.summary.empty()) summary = "found '" + str.substr(pos1, pos2 - pos1) + "'"; else summary = rule.summary; const ErrorLogger::ErrorMessage errmsg(callStack, Severity::fromString(rule.severity), summary, rule.id, false); // Report error reportErr(errmsg); } pcre_free(re); } #endif }
/** * execute_fopen() * * refactor the fopen code for execute into this routine */ URL_FILE * url_execute_fopen(char *url, bool forwrite, extvar_t *ev, CopyState pstate) { URL_EXECUTE_FILE *file; int save_errno; struct itimers savetimers; pqsigfunc save_SIGPIPE; char *cmd; /* Execute command */ Assert(strncmp(url, EXEC_URL_PREFIX, strlen(EXEC_URL_PREFIX)) == 0); cmd = url + strlen(EXEC_URL_PREFIX); file = palloc0(sizeof(URL_EXECUTE_FILE)); file->common.type = CFTYPE_EXEC; /* marked as a EXEC */ file->common.url = pstrdup(url); file->shexec = make_command(cmd, ev); /* Execute command */ /* Clear process interval timers */ resetTimers(&savetimers); if (!execute_resowner_callback_registered) { RegisterResourceReleaseCallback(execute_abort_callback, NULL); execute_resowner_callback_registered = true; } file->handle = create_execute_handle(); /* * Preserve the SIGPIPE handler and set to default handling. This * allows "normal" SIGPIPE handling in the command pipeline. Normal * for PG is to *ignore* SIGPIPE. */ save_SIGPIPE = pqsignal(SIGPIPE, SIG_DFL); /* execute the user command */ file->handle->pid = popen_with_stderr(file->handle->pipes, file->shexec, forwrite); save_errno = errno; /* Restore the SIGPIPE handler */ pqsignal(SIGPIPE, save_SIGPIPE); /* Restore process interval timers */ restoreTimers(&savetimers); if (file->handle->pid == -1) { errno = save_errno; pfree(file->common.url); pfree(file); ereport(ERROR, (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION), errmsg("cannot start external table command: %m"), errdetail("Command: %s", cmd))); } return (URL_FILE *) file; }
/* * - file attribute setting, based on fileMode? */ int pgwin32_open(const char *fileName, int fileFlags,...) { int fd; HANDLE h = INVALID_HANDLE_VALUE; SECURITY_ATTRIBUTES sa; int loops = 0; /* Check that we can handle the request */ assert((fileFlags & ((O_RDONLY | O_WRONLY | O_RDWR) | O_APPEND | (O_RANDOM | O_SEQUENTIAL | O_TEMPORARY) | _O_SHORT_LIVED | O_DSYNC | O_DIRECT | (O_CREAT | O_TRUNC | O_EXCL) | (O_TEXT | O_BINARY))) == fileFlags); sa.nLength = sizeof(sa); sa.bInheritHandle = TRUE; sa.lpSecurityDescriptor = NULL; while ((h = CreateFile(fileName, /* cannot use O_RDONLY, as it == 0 */ (fileFlags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) : ((fileFlags & O_WRONLY) ? GENERIC_WRITE : GENERIC_READ), /* These flags allow concurrent rename/unlink */ (FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE), &sa, openFlagsToCreateFileFlags(fileFlags), FILE_ATTRIBUTE_NORMAL | ((fileFlags & O_RANDOM) ? FILE_FLAG_RANDOM_ACCESS : 0) | ((fileFlags & O_SEQUENTIAL) ? FILE_FLAG_SEQUENTIAL_SCAN : 0) | ((fileFlags & _O_SHORT_LIVED) ? FILE_ATTRIBUTE_TEMPORARY : 0) | ((fileFlags & O_TEMPORARY) ? FILE_FLAG_DELETE_ON_CLOSE : 0) | ((fileFlags & O_DIRECT) ? FILE_FLAG_NO_BUFFERING : 0) | ((fileFlags & O_DSYNC) ? FILE_FLAG_WRITE_THROUGH : 0), NULL)) == INVALID_HANDLE_VALUE) { /* * Sharing violation or locking error can indicate antivirus, backup * or similar software that's locking the file. Try again for 30 * seconds before giving up. */ DWORD err = GetLastError(); if (err == ERROR_SHARING_VIOLATION || err == ERROR_LOCK_VIOLATION) { pg_usleep(100000); loops++; #ifndef FRONTEND if (loops == 50) ereport(LOG, (errmsg("could not open file \"%s\": %s", fileName, (err == ERROR_SHARING_VIOLATION) ? _("sharing violation") : _("lock violation")), errdetail("Continuing to retry for 30 seconds."), errhint("You might have antivirus, backup, or similar software interfering with the database system."))); #endif if (loops < 300) continue; } _dosmaperr(err); return -1; } /* _open_osfhandle will, on error, set errno accordingly */ if ((fd = _open_osfhandle((intptr_t) h, fileFlags & O_APPEND)) < 0) CloseHandle(h); /* will not affect errno */ else if (fileFlags & (O_TEXT | O_BINARY) && _setmode(fd, fileFlags & (O_TEXT | O_BINARY)) < 0) { _close(fd); return -1; } return fd; }
/* * LargeObjectAlterOwner * * Implementation of ALTER LARGE OBJECT statement */ void LargeObjectAlterOwner(Oid loid, Oid newOwnerId) { Form_pg_largeobject_metadata form_lo_meta; Relation pg_lo_meta; ScanKeyData skey[1]; SysScanDesc scan; HeapTuple oldtup; HeapTuple newtup; pg_lo_meta = heap_open(LargeObjectMetadataRelationId, RowExclusiveLock); ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(loid)); scan = systable_beginscan(pg_lo_meta, LargeObjectMetadataOidIndexId, true, SnapshotNow, 1, skey); oldtup = systable_getnext(scan); if (!HeapTupleIsValid(oldtup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("large object %u does not exist", loid))); form_lo_meta = (Form_pg_largeobject_metadata) GETSTRUCT(oldtup); if (form_lo_meta->lomowner != newOwnerId) { Datum values[Natts_pg_largeobject_metadata]; bool nulls[Natts_pg_largeobject_metadata]; bool replaces[Natts_pg_largeobject_metadata]; Acl *newAcl; Datum aclDatum; bool isnull; /* Superusers can always do it */ if (!superuser()) { /* * lo_compat_privileges is not checked here, because ALTER LARGE * OBJECT ... OWNER did not exist at all prior to PostgreSQL 9.0. * * We must be the owner of the existing object. */ if (!pg_largeobject_ownercheck(loid, GetUserId())) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be owner of large object %u", loid))); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); } memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); memset(replaces, false, sizeof(nulls)); values[Anum_pg_largeobject_metadata_lomowner - 1] = ObjectIdGetDatum(newOwnerId); replaces[Anum_pg_largeobject_metadata_lomowner - 1] = true; /* * Determine the modified ACL for the new owner. This is only * necessary when the ACL is non-null. */ aclDatum = heap_getattr(oldtup, Anum_pg_largeobject_metadata_lomacl, RelationGetDescr(pg_lo_meta), &isnull); if (!isnull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), form_lo_meta->lomowner, newOwnerId); values[Anum_pg_largeobject_metadata_lomacl - 1] = PointerGetDatum(newAcl); replaces[Anum_pg_largeobject_metadata_lomacl - 1] = true; } newtup = heap_modify_tuple(oldtup, RelationGetDescr(pg_lo_meta), values, nulls, replaces); simple_heap_update(pg_lo_meta, &newtup->t_self, newtup); CatalogUpdateIndexes(pg_lo_meta, newtup); heap_freetuple(newtup); /* Update owner dependency reference */ changeDependencyOnOwner(LargeObjectRelationId, loid, newOwnerId); } systable_endscan(scan); heap_close(pg_lo_meta, RowExclusiveLock); }
static dyret_enum adjust_therest (int patchcnt, patch_struct *patches) /* We're here because we've successfully patched a singular basis. The patches array contains entries of the form <basis pos'n, x<j>, x<i>>, where x<j> has just been kicked out of the basis and replaced by x<i>. The basis and var2basis vectors are already corrected (we needed them to complete the factorization). Now we need to adjust other dylp data structures to reflect the unexpected change. The amount of additional work to be done depends on the phase of the simplex algorithm. dyINIT: We're done. We've just factored the initial basis and none of the other data structures have been initialised. We didn't really need this call, but the code is cleaner this way. If we're farther along, we might be in the middle of simplex (dyPRIMAL1, dyPRIMAL2, or dyDUAL), or we might be manipulating the constraint system. If we're running simplex, the first actions are cleanup: clear the pivot reject list and back out any antidegeneracy activity. Next, set the status of the newly nonbasic variables, consistent with their previous status. The general rule is to perturb the solution as little as possible. If we're in a primal or dual simplex phase, try to make decisions that are compatible with primal or dual feasibility. Two specific points: * Superbasic (SB) variables are only created in dyPRIMAL2. * Nonbasic free (NBFR) variables imply loss of dual feasibility. Once we have nonbasic status set, we can calculate new primals, duals, and reduced costs and fine-tune the status of the newly basic variables. If we've arrived here from one of the constraint system manipulation phases, there will almost certainly be duplication of effort once we return. But hey, how often does a basis patch happen, anyway? If we're in a simplex phase, there's still some work to do to make the patch as transparent as possible. For dual simplex, we'll check the status of the nonbasic variables and try to maintain dual feasibility. This may not be possible. If we do maintain dual feasibility, reset the DSE norms. For primal simplex, we need to reset the PSE norms. Parameters: patchcnt: the number of basis changes patches: array of basis changes Returns: dyrOK if the repair proceeds without error, dyrLOSTDFEAS if feasibility is lost in dual phase II, and dyrFATAL if anything else goes wrong. */ { int i,j,pndx ; pkvec_struct *aj ; flags statj ; dyret_enum retval ; dyphase_enum phase ; double valj,cbarj,*vub,*vlb,*obj ; const char *rtnnme = "adjust_therest" ; # ifndef DYLP_NDEBUG flags stati ; double vali ; # endif # ifdef DYLP_PARANOIA if (dy_sys == NULL) { errmsg(2,rtnnme,"dy_sys") ; return (dyrFATAL) ; } if (dy_basis == NULL) { errmsg(2,rtnnme,"basis") ; return (dyrFATAL) ; } if (dy_var2basis == NULL) { errmsg(2,rtnnme,"var2basis") ; return (dyrFATAL) ; } if (patches == NULL) { errmsg(2,rtnnme,"patch") ; return (dyrFATAL) ; } # endif phase = dy_lp->phase ; # ifdef DYLP_PARANOIA if (!(phase == dyINIT || phase == dyADDVAR || phase == dyADDCON || phase == dyPRIMAL1 || phase == dyPRIMAL2 || phase == dyDUAL || phase == dyFORCEPRIMAL || phase == dyFORCEDUAL)) { errmsg(1,rtnnme,__LINE__) ; return (dyrFATAL) ; } if (!(phase == dyINIT)) { if (dy_status == NULL) { errmsg(2,rtnnme,"status") ; return (dyrFATAL) ; } if (dy_x == NULL) { errmsg(2,rtnnme,"x") ; return (dyrFATAL) ; } if (dy_xbasic == NULL) { errmsg(2,rtnnme,"x<B>") ; return (dyrFATAL) ; } } #endif if (phase == dyINIT) return (dyrOK) ; vlb = dy_sys->vlb ; vub = dy_sys->vub ; obj = dy_sys->obj ; aj = NULL ; retval = dyrOK ; /* If we're in one of the simplex phases, back out any antidegeneracy activity and clear the pivot rejection list. It's easiest to clear the pivot reject list ahead of the status modifications so that we don't have to worry about the NOPIVOT qualifier when checking status values. */ if (phase == dyPRIMAL1 || phase == dyPRIMAL2 || phase == dyDUAL) { if (dy_clrpivrej(NULL) != TRUE) return (dyrFATAL) ; if (dy_lp->degen > 0) { if (phase == dyDUAL) { (void) dy_dualdegenout(0) ; } else { (void) dy_degenout(0) ; } } } /* Now correct the status for newly nonbasic variables. We need to correct dy_x if the status change forces a change in value. If we end up with a NBFR variable, we've lost dual feasibility. While we're walking the patches, set the status for x<i> (the newly basic variable) to vstatB. No need to be more precise at this point. */ for (pndx = 0 ; pndx < patchcnt ; pndx++) { i = patches[pndx].in ; # ifndef DYLP_NDEBUG stati = dy_status[i] ; vali = dy_x[i] ; # endif dy_status[i] = vstatB ; j = patches[pndx].out ; statj = dy_status[j] ; valj = dy_x[j] ; switch (statj) { case vstatBLLB: { dy_status[j] = vstatNBLB ; dy_x[j] = vlb[j] ; break ; } case vstatBLB: { dy_status[j] = vstatNBLB ; break ; } case vstatB: { if (phase == dyPRIMAL2) dy_status[j] = vstatSB ; else if (valj-vlb[j] < vub[j]-valj) { dy_status[j] = vstatNBLB ; dy_x[j] = vlb[j] ; } else { dy_status[j] = vstatNBUB ; dy_x[j] = vub[j] ; } break ; } case vstatBUB: { dy_status[j] = vstatNBUB ; break ; } case vstatBUUB: { dy_status[j] = vstatNBUB ; dy_x[j] = vub[j] ; break ; } case vstatBFX: { dy_status[j] = vstatNBFX ; break ; } case vstatBFR: { dy_status[j] = vstatNBFR ; if (phase == dyDUAL) { # ifndef DYLP_NDEBUG if (dy_opts->print.dual >= 1) { warn(346,rtnnme, dy_sys->nme,dy_prtlpphase(phase,TRUE),dy_lp->tot.iters+1, dy_prtvstat(statj),consys_nme(dy_sys,'v',j,FALSE,NULL),j) ; } # endif retval = dyrLOSTDFEAS ; } break ; } default: { errmsg(380,rtnnme,dy_sys->nme,consys_nme(dy_sys,'v',j,FALSE,NULL),j, dy_prtvstat(statj),"basic") ; return (dyrFATAL) ; } } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 3) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t%s (%d) had status %s, value %g, ", consys_nme(dy_sys,'v',i,FALSE,NULL),i, dy_prtvstat(stati),vali) ; dyio_outfmt(dy_logchn,dy_gtxecho,"now status %s.", dy_prtvstat(dy_status[i])) ; dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t%s (%d) had status %s, value %g, ", consys_nme(dy_sys,'v',j,FALSE,NULL),j, dy_prtvstat(statj),valj) ; dyio_outfmt(dy_logchn,dy_gtxecho,"now status %s, value %g.", dy_prtvstat(dy_status[j]),dy_x[j]) ; } # endif } # ifdef DYLP_PARANOIA /* If paranoid checks are in place, we need agreement between dy_status, dy_x, and dy_xbasic, lest dy_calccbar fail. Call dy_calcprimals and dy_setbasicstatus to get the basic status right. This is restricted to paranoid mode because the proper place to do this is after making corrections to nonbasic status for dual feasibility. */ if (dy_calcprimals() == FALSE) return (dyrFATAL) ; dy_setbasicstatus() ; # endif /* Calculate the duals and reduced costs. */ dy_calcduals() ; if (dy_calccbar() == FALSE) { errmsg(384,rtnnme, dy_sys->nme,dy_prtlpphase(phase,TRUE),dy_lp->tot.iters) ; return (dyrFATAL) ; } /* If we're in phase dyDUAL, it's worth a scan to check dual feasibility and make adjustments to maintain it, if possible. (retval = dyrLOSTDFEAS says we introduced a NBFR variable, in which case we have no hope). Open a loop to scan the nonbasic variables. NBFX variables are always dual feasible, NBFR variables are never dual feasible. We're minimising, so dual feasibility (primal optimality) is cbarj < 0 && x<j> at upper bound, or cbarj > 0 && x<j> at lower bound. It's important that the zero tolerance for cbar<j> here be the same as the one used in dy_dualin when it checks for loss of dual feasibility. */ if (phase == dyDUAL && retval != dyrLOSTDFEAS) { for (j = 1 ; j <= dy_sys->varcnt ; j++) { statj = dy_status[j] ; if (flgon(statj,vstatBASIC|vstatNBFX)) continue ; if (flgon(statj,vstatNBFR)) { retval = dyrLOSTDFEAS ; # ifndef DYLP_NDEBUG cbarj = dy_cbar[j] ; if (dy_opts->print.dual >= 1) { warn(347,rtnnme, dy_sys->nme,dy_prtlpphase(phase,TRUE),dy_lp->tot.iters+1, consys_nme(dy_sys,'v',j,FALSE,NULL),j, dy_prtvstat(statj),j,cbarj,dy_tols->dfeas) ; } # endif break ; } cbarj = dy_cbar[j] ; if (cbarj < -dy_tols->dfeas && flgoff(statj,vstatNBUB)) { if (vub[j] >= dy_tols->inf) { # ifndef DYLP_NDEBUG if (dy_opts->print.dual >= 1) { warn(347,rtnnme, dy_sys->nme,dy_prtlpphase(phase,TRUE),dy_lp->tot.iters+1, consys_nme(dy_sys,'v',j,FALSE,NULL),j, dy_prtvstat(statj),j,cbarj,dy_tols->dfeas) ; } # endif retval = dyrLOSTDFEAS ; break ; } else { dy_status[j] = vstatNBUB ; dy_x[j] = vub[j] ; } } else if (cbarj > dy_tols->dfeas && flgoff(statj,vstatNBLB)) { if (vlb[j] >= dy_tols->inf) { # ifndef DYLP_NDEBUG if (dy_opts->print.dual >= 1) { warn(347,rtnnme, dy_sys->nme,dy_prtlpphase(phase,TRUE),dy_lp->tot.iters+1, consys_nme(dy_sys,'v',j,FALSE,NULL),j, dy_prtvstat(statj),j,cbarj,dy_tols->dfeas) ; } # endif retval = dyrLOSTDFEAS ; break ; } else { dy_status[j] = vstatNBLB ; dy_x[j] = vlb[j] ; } } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 3 && dy_status[j] != statj) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\tchanged status of %s (%d) from %s to", consys_nme(dy_sys,'v',j,FALSE,NULL),j,dy_prtvstat(statj)) ; dyio_outfmt(dy_logchn,dy_gtxecho, " %s to maintain dual feasibility; cbar = %g.", dy_prtvstat(dy_status[j]),cbarj) ; } # endif } } /* The dual variables and reduced costs have been recalculated, and we have the final status for all nonbasic variables. Recalculate the primal variables and set the status of the basic variables. */ if (dy_calcprimals() == FALSE) return (dyrFATAL) ; dy_setbasicstatus() ; /* If we're running primal simplex, reset the PSE reference frame. If we're running dual simplex and haven't lost dual feasibility, recalculate the basis inverse row norms. */ if (phase == dyPRIMAL1 || phase == dyPRIMAL2) { dy_pseinit() ; } else if (phase == dyDUAL && retval != dyrLOSTDFEAS) { dy_dseinit() ; } return (retval) ; }
Datum internal_kmeans_closest_centroid(PG_FUNCTION_ARGS) { ArrayType *point_array; ArrayType *centroids_array; float8 distance, min_distance = INFINITY; int closest_centroid = 0; int cid; point_array = PG_GETARG_ARRAYTYPE_P(verify_arg_nonnull(fcinfo, 0)); float8* c_point_array = (float8 *)ARR_DATA_PTR(point_array); centroids_array = PG_GETARG_ARRAYTYPE_P(verify_arg_nonnull(fcinfo, 1)); float8* c_centroids_array = (float8 *)ARR_DATA_PTR(centroids_array); int dimension = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 2)); int num_of_centroids = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 3)); int centroids_array_len = num_of_centroids*dimension; int dist_metric = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 4)); ArrayType *canopy_ids_arr = NULL; int32 *canopy_ids = NULL; bool indirect; if (PG_ARGISNULL(5)) { indirect = false; } else { indirect = true; canopy_ids_arr = PG_GETARG_ARRAYTYPE_P(5); /* There should always be a close canopy, but let's be on the safe side. */ if (ARR_NDIM(canopy_ids_arr) == 0) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("internal error: array of close canopies cannot be empty"))); canopy_ids = (int32*) ARR_DATA_PTR(canopy_ids_arr); num_of_centroids = ARR_DIMS(canopy_ids_arr)[0]; } if (dimension < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid dimension:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension))); } if (num_of_centroids < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid num_of_centroids:%d", format_procedure(fcinfo->flinfo->fn_oid), num_of_centroids))); } int array_dim = ARR_NDIM(point_array); int *p_array_dim = ARR_DIMS(point_array); int array_length = ArrayGetNItems(array_dim, p_array_dim); if (array_length != dimension) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid point array length. " "Expected: %d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension, array_length))); } array_dim = ARR_NDIM(centroids_array); p_array_dim = ARR_DIMS(centroids_array); array_length = ArrayGetNItems(array_dim, p_array_dim); if (array_length != centroids_array_len) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid centroids array length. " "Expected: %d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), centroids_array_len, array_length))); } for (int i = 0; i< num_of_centroids; i++) { cid = indirect ? canopy_ids[i] - ARR_LBOUND(canopy_ids_arr)[0] : i; double * centroid = c_centroids_array+cid*dimension; MetricFunc func = get_metric_fn_for_array(dist_metric); distance = (*func)(centroid, c_point_array, dimension); if (distance < min_distance) { closest_centroid = cid; min_distance = distance; } } PG_RETURN_INT32(closest_centroid+ARR_LBOUND(centroids_array)[0]); }
/* cash_in() * Convert a string to a cash data type. * Format is [$]###[,]###[.##] * Examples: 123.45 $123.45 $123,456.78 * */ Datum cash_in(PG_FUNCTION_ARGS) { char *str = PG_GETARG_CSTRING(0); Cash result; Cash value = 0; Cash dec = 0; Cash sgn = 1; int seen_dot = 0; const char *s = str; int fpoint; char dsymbol, ssymbol, psymbol; const char *nsymbol, *csymbol; struct lconv *lconvert = PGLC_localeconv(); /* * frac_digits will be CHAR_MAX in some locales, notably C. However, just * testing for == CHAR_MAX is risky, because of compilers like gcc that * "helpfully" let you alter the platform-standard definition of whether * char is signed or not. If we are so unfortunate as to get compiled * with a nonstandard -fsigned-char or -funsigned-char switch, then our * idea of CHAR_MAX will not agree with libc's. The safest course is not * to test for CHAR_MAX at all, but to impose a range check for plausible * frac_digits values. */ fpoint = lconvert->frac_digits; if (fpoint < 0 || fpoint > 10) fpoint = 2; /* best guess in this case, I think */ dsymbol = ((*lconvert->mon_decimal_point != '\0') ? *lconvert->mon_decimal_point : '.'); if (*lconvert->mon_thousands_sep != '\0') ssymbol = *lconvert->mon_thousands_sep; else /* ssymbol should not equal dsymbol */ ssymbol = (dsymbol != ',') ? ',' : '.'; csymbol = ((*lconvert->currency_symbol != '\0') ? lconvert->currency_symbol : "$"); psymbol = ((*lconvert->positive_sign != '\0') ? *lconvert->positive_sign : '+'); nsymbol = ((*lconvert->negative_sign != '\0') ? lconvert->negative_sign : "-"); #ifdef CASHDEBUG printf("cashin- precision '%d'; decimal '%c'; thousands '%c'; currency '%s'; positive '%c'; negative '%s'\n", fpoint, dsymbol, ssymbol, csymbol, psymbol, nsymbol); #endif /* we need to add all sorts of checking here. For now just */ /* strip all leading whitespace and any leading currency symbol */ while (isspace((unsigned char) *s)) s++; if (strncmp(s, csymbol, strlen(csymbol)) == 0) s += strlen(csymbol); #ifdef CASHDEBUG printf("cashin- string is '%s'\n", s); #endif /* a leading minus or paren signifies a negative number */ /* again, better heuristics needed */ /* XXX - doesn't properly check for balanced parens - djmc */ if (strncmp(s, nsymbol, strlen(nsymbol)) == 0) { sgn = -1; s += strlen(nsymbol); #ifdef CASHDEBUG printf("cashin- negative symbol; string is '%s'\n", s); #endif } else if (*s == '(') { sgn = -1; s++; } else if (*s == psymbol) s++; #ifdef CASHDEBUG printf("cashin- string is '%s'\n", s); #endif while (isspace((unsigned char) *s)) s++; if (strncmp(s, csymbol, strlen(csymbol)) == 0) s += strlen(csymbol); #ifdef CASHDEBUG printf("cashin- string is '%s'\n", s); #endif for (;; s++) { /* we look for digits as long as we have found less */ /* than the required number of decimal places */ if (isdigit((unsigned char) *s) && (!seen_dot || dec < fpoint)) { value = (value * 10) + (*s - '0'); if (seen_dot) dec++; } /* decimal point? then start counting fractions... */ else if (*s == dsymbol && !seen_dot) { seen_dot = 1; } /* ignore if "thousands" separator, else we're done */ else if (*s != ssymbol) { /* round off */ if (isdigit((unsigned char) *s) && *s >= '5') value++; /* adjust for less than required decimal places */ for (; dec < fpoint; dec++) value *= 10; break; } } /* should only be trailing digits followed by whitespace or right paren */ while (isdigit((unsigned char) *s)) s++; while (isspace((unsigned char) *s) || *s == ')') s++; if (*s != '\0') ereport(ERROR, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("invalid input syntax for type money: \"%s\"", str))); result = value * sgn; #ifdef CASHDEBUG printf("cashin- result is " INT64_FORMAT "\n", result); #endif PG_RETURN_CASH(result); }
/* * parsetinterval -- parse a tinterval string * * output parameters: * i_start, i_end: tinterval margins * * Time interval: * `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]' * * OR `Undefined Range' (see also INVALID_INTERVAL_STR) * * where <AbsTime> satisfies the syntax of absolute time. * * e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970'] */ static void parsetinterval(char *i_string, AbsoluteTime *i_start, AbsoluteTime *i_end) { char *p, *p1; char c; p = i_string; /* skip leading blanks up to '[' */ while ((c = *p) != '\0') { if (IsSpace(c)) p++; else if (c != '[') goto bogus; /* syntax error */ else break; } if (c == '\0') goto bogus; /* syntax error */ p++; /* skip leading blanks up to '"' */ while ((c = *p) != '\0') { if (IsSpace(c)) p++; else if (c != '"') goto bogus; /* syntax error */ else break; } if (c == '\0') goto bogus; /* syntax error */ p++; if (strncmp(INVALID_INTERVAL_STR, p, strlen(INVALID_INTERVAL_STR)) == 0) goto bogus; /* undefined range, handled like a syntax err. */ /* search for the end of the first date and change it to a \0 */ p1 = p; while ((c = *p1) != '\0') { if (c == '"') break; p1++; } if (c == '\0') goto bogus; /* syntax error */ *p1 = '\0'; /* get the first date */ *i_start = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein, CStringGetDatum(p))); /* undo change to \0 */ *p1 = c; p = ++p1; /* skip blanks up to '"', beginning of second date */ while ((c = *p) != '\0') { if (IsSpace(c)) p++; else if (c != '"') goto bogus; /* syntax error */ else break; } if (c == '\0') goto bogus; /* syntax error */ p++; /* search for the end of the second date and change it to a \0 */ p1 = p; while ((c = *p1) != '\0') { if (c == '"') break; p1++; } if (c == '\0') goto bogus; /* syntax error */ *p1 = '\0'; /* get the second date */ *i_end = DatumGetAbsoluteTime(DirectFunctionCall1(abstimein, CStringGetDatum(p))); /* undo change to \0 */ *p1 = c; p = ++p1; /* skip blanks up to ']' */ while ((c = *p) != '\0') { if (IsSpace(c)) p++; else if (c != ']') goto bogus; /* syntax error */ else break; } if (c == '\0') goto bogus; /* syntax error */ p++; c = *p; if (c != '\0') goto bogus; /* syntax error */ /* it seems to be a valid tinterval */ return; bogus: ereport(ERROR, (errcode(ERRCODE_INVALID_DATETIME_FORMAT), errmsg("invalid input syntax for type tinterval: \"%s\"", i_string))); *i_start = *i_end = INVALID_ABSTIME; /* keep compiler quiet */ }
/* * Main entry point for syslogger process * argc/argv parameters are valid only in EXEC_BACKEND case. */ NON_EXEC_STATIC void SysLoggerMain(int argc, char *argv[]) { #ifndef WIN32 char logbuffer[READ_BUF_SIZE]; int bytes_in_logbuffer = 0; #endif char *currentLogDir; char *currentLogFilename; int currentLogRotationAge; IsUnderPostmaster = true; /* we are a postmaster subprocess now */ MyProcPid = getpid(); /* reset MyProcPid */ MyStartTime = time(NULL); /* set our start time in case we call elog */ #ifdef EXEC_BACKEND syslogger_parseArgs(argc, argv); #endif /* EXEC_BACKEND */ am_syslogger = true; init_ps_display("logger process", "", "", ""); /* * If we restarted, our stderr is already redirected into our own input * pipe. This is of course pretty useless, not to mention that it * interferes with detecting pipe EOF. Point stderr to /dev/null. This * assumes that all interesting messages generated in the syslogger will * come through elog.c and will be sent to write_syslogger_file. */ if (redirection_done) { int fd = open(DEVNULL, O_WRONLY, 0); /* * The closes might look redundant, but they are not: we want to be * darn sure the pipe gets closed even if the open failed. We can * survive running with stderr pointing nowhere, but we can't afford * to have extra pipe input descriptors hanging around. */ close(fileno(stdout)); close(fileno(stderr)); if (fd != -1) { dup2(fd, fileno(stdout)); dup2(fd, fileno(stderr)); close(fd); } } /* * Syslogger's own stderr can't be the syslogPipe, so set it back to text * mode if we didn't just close it. (It was set to binary in * SubPostmasterMain). */ #ifdef WIN32 else _setmode(_fileno(stderr), _O_TEXT); #endif /* * Also close our copy of the write end of the pipe. This is needed to * ensure we can detect pipe EOF correctly. (But note that in the restart * case, the postmaster already did this.) */ #ifndef WIN32 if (syslogPipe[1] >= 0) close(syslogPipe[1]); syslogPipe[1] = -1; #else if (syslogPipe[1]) CloseHandle(syslogPipe[1]); syslogPipe[1] = 0; #endif /* * If possible, make this process a group leader, so that the postmaster * can signal any child processes too. (syslogger probably never has any * child processes, but for consistency we make all postmaster child * processes do this.) */ #ifdef HAVE_SETSID if (setsid() < 0) elog(FATAL, "setsid() failed: %m"); #endif /* * Properly accept or ignore signals the postmaster might send us * * Note: we ignore all termination signals, and instead exit only when all * upstream processes are gone, to ensure we don't miss any dying gasps of * broken backends... */ pqsignal(SIGHUP, sigHupHandler); /* set flag to read config file */ pqsignal(SIGINT, SIG_IGN); pqsignal(SIGTERM, SIG_IGN); pqsignal(SIGQUIT, SIG_IGN); pqsignal(SIGALRM, SIG_IGN); pqsignal(SIGPIPE, SIG_IGN); pqsignal(SIGUSR1, sigUsr1Handler); /* request log rotation */ pqsignal(SIGUSR2, SIG_IGN); /* * Reset some signals that are accepted by postmaster but not here */ pqsignal(SIGCHLD, SIG_DFL); pqsignal(SIGTTIN, SIG_DFL); pqsignal(SIGTTOU, SIG_DFL); pqsignal(SIGCONT, SIG_DFL); pqsignal(SIGWINCH, SIG_DFL); PG_SETMASK(&UnBlockSig); #ifdef WIN32 /* Fire up separate data transfer thread */ InitializeCriticalSection(&sysloggerSection); EnterCriticalSection(&sysloggerSection); threadHandle = (HANDLE) _beginthreadex(NULL, 0, pipeThread, NULL, 0, NULL); if (threadHandle == 0) elog(FATAL, "could not create syslogger data transfer thread: %m"); #endif /* WIN32 */ /* remember active logfile parameters */ currentLogDir = pstrdup(Log_directory); currentLogFilename = pstrdup(Log_filename); currentLogRotationAge = Log_RotationAge; /* set next planned rotation time */ set_next_rotation_time(); /* main worker loop */ for (;;) { bool time_based_rotation = false; int size_rotation_for = 0; #ifndef WIN32 int bytesRead; int rc; fd_set rfds; struct timeval timeout; #endif if (got_SIGHUP) { got_SIGHUP = false; ProcessConfigFile(PGC_SIGHUP); /* * Check if the log directory or filename pattern changed in * postgresql.conf. If so, force rotation to make sure we're * writing the logfiles in the right place. */ if (strcmp(Log_directory, currentLogDir) != 0) { pfree(currentLogDir); currentLogDir = pstrdup(Log_directory); rotation_requested = true; } if (strcmp(Log_filename, currentLogFilename) != 0) { pfree(currentLogFilename); currentLogFilename = pstrdup(Log_filename); rotation_requested = true; } /* * If rotation time parameter changed, reset next rotation time, * but don't immediately force a rotation. */ if (currentLogRotationAge != Log_RotationAge) { currentLogRotationAge = Log_RotationAge; set_next_rotation_time(); } } if (!rotation_requested && Log_RotationAge > 0) { /* Do a logfile rotation if it's time */ pg_time_t now = (pg_time_t) time(NULL); if (now >= next_rotation_time) rotation_requested = time_based_rotation = true; } if (!rotation_requested && Log_RotationSize > 0) { /* Do a rotation if file is too big */ if (ftell(syslogFile) >= Log_RotationSize * 1024L) { rotation_requested = true; size_rotation_for |= LOG_DESTINATION_STDERR; } if (csvlogFile != NULL && ftell(csvlogFile) >= Log_RotationSize * 1024L) { rotation_requested = true; size_rotation_for |= LOG_DESTINATION_CSVLOG; } } if (rotation_requested) { /* * Force rotation when both values are zero. It means the request * was sent by pg_rotate_logfile. */ if (!time_based_rotation && size_rotation_for == 0) size_rotation_for = LOG_DESTINATION_STDERR | LOG_DESTINATION_CSVLOG; logfile_rotate(time_based_rotation, size_rotation_for); } #ifndef WIN32 /* * Wait for some data, timing out after 1 second */ FD_ZERO(&rfds); FD_SET(syslogPipe[0], &rfds); timeout.tv_sec = 1; timeout.tv_usec = 0; rc = select(syslogPipe[0] + 1, &rfds, NULL, NULL, &timeout); if (rc < 0) { if (errno != EINTR) ereport(LOG, (errcode_for_socket_access(), errmsg("select() failed in logger process: %m"))); } else if (rc > 0 && FD_ISSET(syslogPipe[0], &rfds)) { bytesRead = piperead(syslogPipe[0], logbuffer + bytes_in_logbuffer, sizeof(logbuffer) - bytes_in_logbuffer); if (bytesRead < 0) { if (errno != EINTR) ereport(LOG, (errcode_for_socket_access(), errmsg("could not read from logger pipe: %m"))); } else if (bytesRead > 0) { bytes_in_logbuffer += bytesRead; process_pipe_input(logbuffer, &bytes_in_logbuffer); continue; } else { /* * Zero bytes read when select() is saying read-ready means * EOF on the pipe: that is, there are no longer any processes * with the pipe write end open. Therefore, the postmaster * and all backends are shut down, and we are done. */ pipe_eof_seen = true; /* if there's any data left then force it out now */ flush_pipe_input(logbuffer, &bytes_in_logbuffer); } } #else /* WIN32 */ /* * On Windows we leave it to a separate thread to transfer data and * detect pipe EOF. The main thread just wakes up once a second to * check for SIGHUP and rotation conditions. * * Server code isn't generally thread-safe, so we ensure that only one * of the threads is active at a time by entering the critical section * whenever we're not sleeping. */ LeaveCriticalSection(&sysloggerSection); pg_usleep(1000000L); EnterCriticalSection(&sysloggerSection); #endif /* WIN32 */ if (pipe_eof_seen) { /* * seeing this message on the real stderr is annoying - so we make * it DEBUG1 to suppress in normal use. */ ereport(DEBUG1, (errmsg("logger shutting down"))); /* * Normal exit from the syslogger is here. Note that we * deliberately do not close syslogFile before exiting; this is to * allow for the possibility of elog messages being generated * inside proc_exit. Regular exit() will take care of flushing * and closing stdio channels. */ proc_exit(0); } } }
/* * Postmaster subroutine to start a syslogger subprocess. */ int SysLogger_Start(void) { pid_t sysloggerPid; char *filename; if (!Logging_collector) return 0; /* * If first time through, create the pipe which will receive stderr * output. * * If the syslogger crashes and needs to be restarted, we continue to use * the same pipe (indeed must do so, since extant backends will be writing * into that pipe). * * This means the postmaster must continue to hold the read end of the * pipe open, so we can pass it down to the reincarnated syslogger. This * is a bit klugy but we have little choice. */ #ifndef WIN32 if (syslogPipe[0] < 0) { if (pgpipe(syslogPipe) < 0) ereport(FATAL, (errcode_for_socket_access(), (errmsg("could not create pipe for syslog: %m")))); } #else if (!syslogPipe[0]) { SECURITY_ATTRIBUTES sa; memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; if (!CreatePipe(&syslogPipe[0], &syslogPipe[1], &sa, 32768)) ereport(FATAL, (errcode_for_file_access(), (errmsg("could not create pipe for syslog: %m")))); } #endif /* * Create log directory if not present; ignore errors */ mkdir(Log_directory, 0700); /* * The initial logfile is created right in the postmaster, to verify that * the Log_directory is writable. */ filename = logfile_getname(time(NULL), NULL); syslogFile = logfile_open(filename, "a", false); pfree(filename); #ifdef EXEC_BACKEND switch ((sysloggerPid = syslogger_forkexec())) #else switch ((sysloggerPid = fork_process())) #endif { case -1: ereport(LOG, (errmsg("could not fork system logger: %m"))); return 0; #ifndef EXEC_BACKEND case 0: /* in postmaster child ... */ /* Close the postmaster's sockets */ ClosePostmasterPorts(true); /* Lose the postmaster's on-exit routines */ on_exit_reset(); /* Drop our connection to postmaster's shared memory, as well */ PGSharedMemoryDetach(); /* do the work */ SysLoggerMain(0, NULL); break; #endif default: /* success, in postmaster */ /* now we redirect stderr, if not done already */ if (!redirection_done) { #ifndef WIN32 fflush(stdout); if (dup2(syslogPipe[1], fileno(stdout)) < 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not redirect stdout: %m"))); fflush(stderr); if (dup2(syslogPipe[1], fileno(stderr)) < 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not redirect stderr: %m"))); /* Now we are done with the write end of the pipe. */ close(syslogPipe[1]); syslogPipe[1] = -1; #else int fd; /* * open the pipe in binary mode and make sure stderr is binary * after it's been dup'ed into, to avoid disturbing the pipe * chunking protocol. */ fflush(stderr); fd = _open_osfhandle((intptr_t) syslogPipe[1], _O_APPEND | _O_BINARY); if (dup2(fd, _fileno(stderr)) < 0) ereport(FATAL, (errcode_for_file_access(), errmsg("could not redirect stderr: %m"))); close(fd); _setmode(_fileno(stderr), _O_BINARY); /* Now we are done with the write end of the pipe. */ CloseHandle(syslogPipe[1]); syslogPipe[1] = 0; #endif redirection_done = true; } /* postmaster will never write the file; close it */ fclose(syslogFile); syslogFile = NULL; return (int) sysloggerPid; } /* we should never reach here */ return 0; }
/* * perform logfile rotation */ static void logfile_rotate(bool time_based_rotation, int size_rotation_for) { char *filename; char *csvfilename = NULL; pg_time_t fntime; FILE *fh; rotation_requested = false; /* * When doing a time-based rotation, invent the new logfile name based on * the planned rotation time, not current time, to avoid "slippage" in the * file name when we don't do the rotation immediately. */ if (time_based_rotation) fntime = next_rotation_time; else fntime = time(NULL); filename = logfile_getname(fntime, NULL); if (csvlogFile != NULL) csvfilename = logfile_getname(fntime, ".csv"); /* * Decide whether to overwrite or append. We can overwrite if (a) * Log_truncate_on_rotation is set, (b) the rotation was triggered by * elapsed time and not something else, and (c) the computed file name is * different from what we were previously logging into. * * Note: during the first rotation after forking off from the postmaster, * last_file_name will be NULL. (We don't bother to set it in the * postmaster because it ain't gonna work in the EXEC_BACKEND case.) So we * will always append in that situation, even though truncating would * usually be safe. * * For consistency, we treat CSV logs the same even though they aren't * opened in the postmaster. */ if (time_based_rotation || (size_rotation_for & LOG_DESTINATION_STDERR)) { if (Log_truncate_on_rotation && time_based_rotation && last_file_name != NULL && strcmp(filename, last_file_name) != 0) fh = logfile_open(filename, "w", true); else fh = logfile_open(filename, "a", true); if (!fh) { /* * ENFILE/EMFILE are not too surprising on a busy system; just * keep using the old file till we manage to get a new one. * Otherwise, assume something's wrong with Log_directory and stop * trying to create files. */ if (errno != ENFILE && errno != EMFILE) { ereport(LOG, (errmsg("disabling automatic rotation (use SIGHUP to re-enable)"))); Log_RotationAge = 0; Log_RotationSize = 0; } if (filename) pfree(filename); if (csvfilename) pfree(csvfilename); return; } fclose(syslogFile); syslogFile = fh; /* instead of pfree'ing filename, remember it for next time */ if (last_file_name != NULL) pfree(last_file_name); last_file_name = filename; filename = NULL; } /* Same as above, but for csv file. */ if (csvlogFile != NULL && (time_based_rotation || (size_rotation_for & LOG_DESTINATION_CSVLOG))) { if (Log_truncate_on_rotation && time_based_rotation && last_csv_file_name != NULL && strcmp(csvfilename, last_csv_file_name) != 0) fh = logfile_open(csvfilename, "w", true); else fh = logfile_open(csvfilename, "a", true); if (!fh) { /* * ENFILE/EMFILE are not too surprising on a busy system; just * keep using the old file till we manage to get a new one. * Otherwise, assume something's wrong with Log_directory and stop * trying to create files. */ if (errno != ENFILE && errno != EMFILE) { ereport(LOG, (errmsg("disabling automatic rotation (use SIGHUP to re-enable)"))); Log_RotationAge = 0; Log_RotationSize = 0; } if (filename) pfree(filename); if (csvfilename) pfree(csvfilename); return; } fclose(csvlogFile); csvlogFile = fh; /* instead of pfree'ing filename, remember it for next time */ if (last_csv_file_name != NULL) pfree(last_csv_file_name); last_csv_file_name = csvfilename; csvfilename = NULL; } if (filename) pfree(filename); if (csvfilename) pfree(csvfilename); set_next_rotation_time(); }
/* * RequestCheckpoint * Called in backend processes to request a checkpoint * * flags is a bitwise OR of the following: * CHECKPOINT_IS_SHUTDOWN: checkpoint is for database shutdown. * CHECKPOINT_END_OF_RECOVERY: checkpoint is for end of WAL recovery. * CHECKPOINT_IMMEDIATE: finish the checkpoint ASAP, * ignoring checkpoint_completion_target parameter. * CHECKPOINT_FORCE: force a checkpoint even if no XLOG activity has occured * since the last one (implied by CHECKPOINT_IS_SHUTDOWN or * CHECKPOINT_END_OF_RECOVERY). * CHECKPOINT_WAIT: wait for completion before returning (otherwise, * just signal bgwriter to do it, and return). * CHECKPOINT_CAUSE_XLOG: checkpoint is requested due to xlog filling. * (This affects logging, and in particular enables CheckPointWarning.) */ void RequestCheckpoint(int flags) { /* use volatile pointer to prevent code rearrangement */ volatile BgWriterShmemStruct *bgs = BgWriterShmem; int ntries; int old_failed, old_started; /* * If in a standalone backend, just do it ourselves. */ if (!IsPostmasterEnvironment) { /* * There's no point in doing slow checkpoints in a standalone backend, * because there's no other backends the checkpoint could disrupt. */ CreateCheckPoint(flags | CHECKPOINT_IMMEDIATE); /* * After any checkpoint, close all smgr files. This is so we won't * hang onto smgr references to deleted files indefinitely. */ smgrcloseall(); return; } /* * Atomically set the request flags, and take a snapshot of the counters. * When we see ckpt_started > old_started, we know the flags we set here * have been seen by bgwriter. * * Note that we OR the flags with any existing flags, to avoid overriding * a "stronger" request by another backend. The flag senses must be * chosen to make this work! */ SpinLockAcquire(&bgs->ckpt_lck); old_failed = bgs->ckpt_failed; old_started = bgs->ckpt_started; bgs->ckpt_flags |= flags; SpinLockRelease(&bgs->ckpt_lck); /* * Send signal to request checkpoint. It's possible that the bgwriter * hasn't started yet, or is in process of restarting, so we will retry a * few times if needed. Also, if not told to wait for the checkpoint to * occur, we consider failure to send the signal to be nonfatal and merely * LOG it. */ for (ntries = 0;; ntries++) { if (BgWriterShmem->checkpointer_pid == 0) { if (ntries >= 20) /* max wait 2.0 sec */ { elog((flags & CHECKPOINT_WAIT) ? ERROR : LOG, "could not request checkpoint because checkpointer not running"); break; } } else if (kill(BgWriterShmem->checkpointer_pid, SIGINT) != 0) { if (ntries >= 20) /* max wait 2.0 sec */ { elog((flags & CHECKPOINT_WAIT) ? ERROR : LOG, "could not signal for checkpoint: %m"); break; } } else break; /* signal sent successfully */ CHECK_FOR_INTERRUPTS(); pg_usleep(100000L); /* wait 0.1 sec, then retry */ } /* * If requested, wait for completion. We detect completion according to * the algorithm given above. */ if (flags & CHECKPOINT_WAIT) { int new_started, new_failed; /* Wait for a new checkpoint to start. */ for (;;) { SpinLockAcquire(&bgs->ckpt_lck); new_started = bgs->ckpt_started; SpinLockRelease(&bgs->ckpt_lck); if (new_started != old_started) break; CHECK_FOR_INTERRUPTS(); pg_usleep(100000L); } /* * We are waiting for ckpt_done >= new_started, in a modulo sense. */ for (;;) { int new_done; SpinLockAcquire(&bgs->ckpt_lck); new_done = bgs->ckpt_done; new_failed = bgs->ckpt_failed; SpinLockRelease(&bgs->ckpt_lck); if (new_done - new_started >= 0) break; CHECK_FOR_INTERRUPTS(); pg_usleep(100000L); } if (new_failed != old_failed) ereport(ERROR, (errmsg("checkpoint request failed"), errhint("Consult recent messages in the server log for details."))); } }
/* * CompactCheckpointerRequestQueue * Remove duplicates from the request queue to avoid backend fsyncs. * * Although a full fsync request queue is not common, it can lead to severe * performance problems when it does happen. So far, this situation has * only been observed to occur when the system is under heavy write load, * and especially during the "sync" phase of a checkpoint. Without this * logic, each backend begins doing an fsync for every block written, which * gets very expensive and can slow down the whole system. * * Trying to do this every time the queue is full could lose if there * aren't any removable entries. But should be vanishingly rare in * practice: there's one queue entry per shared buffer. */ static bool CompactCheckpointerRequestQueue() { struct BgWriterSlotMapping { BgWriterRequest request; int slot; }; int n, preserve_count; int num_skipped = 0; HASHCTL ctl; HTAB *htab; bool *skip_slot; /* must hold BgWriterCommLock in exclusive mode */ Assert(LWLockHeldByMe(BgWriterCommLock)); /* Initialize temporary hash table */ MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(BgWriterRequest); ctl.entrysize = sizeof(struct BgWriterSlotMapping); ctl.hash = tag_hash; htab = hash_create("CompactBgwriterRequestQueue", BgWriterShmem->num_requests, &ctl, HASH_ELEM | HASH_FUNCTION); /* Initialize skip_slot array */ skip_slot = palloc0(sizeof(bool) * BgWriterShmem->num_requests); /* * The basic idea here is that a request can be skipped if it's followed * by a later, identical request. It might seem more sensible to work * backwards from the end of the queue and check whether a request is * *preceded* by an earlier, identical request, in the hopes of doing less * copying. But that might change the semantics, if there's an * intervening FORGET_RELATION_FSYNC or FORGET_DATABASE_FSYNC request, so * we do it this way. It would be possible to be even smarter if we made * the code below understand the specific semantics of such requests (it * could blow away preceding entries that would end up being canceled * anyhow), but it's not clear that the extra complexity would buy us * anything. */ for (n = 0; n < BgWriterShmem->num_requests; ++n) { BgWriterRequest *request; struct BgWriterSlotMapping *slotmap; bool found; request = &BgWriterShmem->requests[n]; slotmap = hash_search(htab, request, HASH_ENTER, &found); if (found) { skip_slot[slotmap->slot] = true; ++num_skipped; } slotmap->slot = n; } /* Done with the hash table. */ hash_destroy(htab); /* If no duplicates, we're out of luck. */ if (!num_skipped) { pfree(skip_slot); return false; } /* We found some duplicates; remove them. */ for (n = 0, preserve_count = 0; n < BgWriterShmem->num_requests; ++n) { if (skip_slot[n]) continue; BgWriterShmem->requests[preserve_count++] = BgWriterShmem->requests[n]; } ereport(DEBUG1, (errmsg("compacted fsync request queue from %d entries to %d entries", BgWriterShmem->num_requests, preserve_count))); BgWriterShmem->num_requests = preserve_count; /* Cleanup. */ pfree(skip_slot); return true; }
void dy_initbasis (int concnt, int factor, double zero_tol) /* This routine calls the glpk routine inv_create to initialize the basis data structures, then sets values for the zero tolerance (eps_tol), pivot ratio (piv_tol) and number of candidates examined (piv_lim). NOTE: This routine can be (and typically is) called before any of the main dylp data structures exist. Be careful what you reference. Parameters: concnt: the number of constraints (rows) that the basis representation should be capable of handling factor: the planned refactorisation frequency; passed to glpk as the basis inverse update capacity (i.e., the limit on the number of pivots between refactorisations) zero_tol: zero tolerance; a value of 0.0 uses the glpk default (INV->LUF->eps_tol = 1.0e-15). Returns: void */ { int sva_size ; const char *rtnnme = "dy_initbasis" ; /* Create the basis. Allow for at least five constraints (also handles pathological examples with no explicit constraints). */ luf_capacity = maxx(concnt,5) ; luf_basis = inv_create(luf_capacity,factor) ; if (luf_basis == NULL) { if (dy_lp == NULL) { errmsg(302,rtnnme,"empty","pre-init",0,"create") ; } else { errmsg(302,rtnnme,dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters,"create") ; } return ; } /* WARNING: We're going to reach inside glpluf to get it to triple the amount of space that it allocates for the sparse vector area. We're doing this by triggering the reallocation mechanism built into luf_decomp (called by inv_decomp). */ sva_size = luf_basis->luf->sv_size ; luf_basis->luf->new_sva = 3*sva_size ; # ifndef DYLP_NDEBUG if (dy_opts != NULL && dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\ninitbasis: %s(%d) basis capacity %d, piv lim %d.", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters, luf_basis->luf->n,luf_basis->hh_max) ; } /* XX_DEBUG_XX There's no good way to control this output, given the timing of the call (before dy_opts is initialised), but it's sometimes useful when debugging. else { dyio_outfmt(dy_logchn,TRUE, "\ninitbasis: EXTERN(0) basis capacity %d, piv lim %d.", luf_basis->luf->n,luf_basis->hh_max) ; } */ # endif /* Set the initial pivot level to {.01,4}, and allow it to drop to {.01,4}. */ pivlevel = 0 ; minpivlevel = 0 ; if (zero_tol != 0.0) luf_basis->luf->eps_tol = zero_tol ; luf_basis->luf->piv_tol = pivtols[pivlevel].stable ; luf_basis->luf->piv_lim = pivtols[pivlevel].look ; luf_basis->luf->max_gro = 1.0e7 ; /* This is the smallest value that can appear on the diagonal of U after a pivot update. dylp will (in extremis) drop its pivot selection tolerance tols.pivot to 1e-9 (or thereabouts), so upd_tol had better be less or we spend a lot of time refactoring. This should probably be adjusted as needed, in response to adjustments in tols.pivot, but I need to sit down and really think about the math. In the meantime, this seems to be adequate. */ luf_basis->upd_tol = 1.0e-10 ; return ; }
/* * Opens an existing work file with the specified name, the file type, * and the compression type. * * If this fails, NULL is returned. */ ExecWorkFile * ExecWorkFile_Open(const char *fileName, ExecWorkFileType fileType, bool delOnClose, int compressType) { ExecWorkFile *workfile = NULL; void *file = NULL; int64 file_size = 0; /* * Create ExecWorkFile in the TopMemoryContext since this memory context * is still available when calling the transaction callback at the * time when the transaction aborts. */ MemoryContext oldContext = MemoryContextSwitchTo(TopMemoryContext); switch(fileType) { case BUFFILE: file = (void *)BufFileOpenFile(fileName, false, /* Create */ delOnClose, true /* interXact */ ); if (!file) { elog(ERROR, "could not open temporary file \"%s\": %m", fileName); } BufFileSetWorkfile(file); file_size = BufFileGetSize(file); break; case BFZ: file = (void *)bfz_open(fileName, delOnClose, compressType); if (!file) { elog(ERROR, "could not open temporary file \"%s\": %m", fileName); } file_size = bfz_totalbytes((bfz_t *)file); break; default: ereport(LOG, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("invalid work file type: %d", fileType))); Assert(false); } /* Failed opening existing workfile. Inform the caller */ if (NULL == file) { MemoryContextSwitchTo(oldContext); return NULL; } workfile = palloc0(sizeof(ExecWorkFile)); workfile->fileType = fileType; workfile->compressType = compressType; workfile->file = file; workfile->fileName = pstrdup(fileName); workfile->size = file_size; ExecWorkFile_SetFlags(workfile, delOnClose, false /* created */); MemoryContextSwitchTo(oldContext); return workfile; }
static void adjust_basis (int *p_patchcnt, patch_struct **p_patches) /* This routine corrects the dylp basis arrays when glpinv/glpluf declares the current basis to be singular. glpluf doesn't actually salvage the basis --- it just reports the linearly dependent (hence unpivoted) columns and corresponding unpivoted rows. Once we've adjusted the basis accordingly, we can make another attempt to factor. The convention is as follows: luf_basis.rank gives the rank of the basis. qq_col[rank+1 .. m] contain the indices of the basic columns that must be removed from the basis. pp_row[rank+1 .. m] contain the indices of the basic rows that remain unpivoted; we'll put the logicals for these rows into the basis. Both of the above are expressed in terms of basis positions. For the rows, basis position i is equivalent to constraint i; for the columns, we need to look up the variable j in basis position i. Recognise that in general this is the easiest part of salvaging the situation. We record the changes for adjust_therest, which will do the remainder of the work after the basis is successfully factored. Parameters: p_patchcnt: (o) the number of basis corrections p_patches: (o) patch array recording the basis corrections Returns: undefined */ { int *qq_col, *pp_row ; int rank,pqndx,i,j,k,pndx ; patch_struct *patches ; #if defined(DYLP_PARANOIA) || MALLOC_DEBUG == 2 const char *rtnnme = "adjust_basis" ; if (dy_sys == NULL) { errmsg(2,rtnnme,"dy_sys") ; return ; } if (dy_basis == NULL) { errmsg(2,rtnnme,"basis") ; return ; } if (dy_var2basis == NULL) { errmsg(2,rtnnme,"var2basis") ; return ; } if (luf_basis == NULL) { errmsg(2,rtnnme,"LUF basis") ; return ; } if (p_patches == NULL) { errmsg(2,rtnnme,"p_patches") ; return ; } #endif qq_col = luf_basis->luf->qq_col ; pp_row = luf_basis->luf->pp_row ; rank = luf_basis->luf->rank ; patches = (patch_struct *) MALLOC((dy_sys->concnt-rank)*sizeof(patch_struct)) ; /* Walk qq_col, retrieving the basis position that must be corrected. Remove the corresponding variable from the basis, and put in its place the slack for the basis row. */ for (pqndx = rank+1, pndx = 0 ; pqndx <= dy_sys->concnt ; pqndx++, pndx++) { k = qq_col[pqndx] ; j = dy_basis[k] ; i = pp_row[pqndx] ; dy_basis[k] = i ; dy_var2basis[j] = 0 ; dy_var2basis[i] = k ; patches[pndx].pos = k ; patches[pndx].out = j ; patches[pndx].in = i ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 3) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n pos'n %d (%s (%d)) replacing %s (%d) with %s (%d).", k,consys_nme(dy_sys,'c',k,FALSE,NULL),k, consys_nme(dy_sys,'v',j,FALSE,NULL),j, consys_nme(dy_sys,'v',i,FALSE,NULL),i) ; } # endif } *p_patchcnt = pndx ; *p_patches = patches ; return ; }
/* * Accumulate a new datum for one AO storage option. */ static void accumAOStorageOpt(char *name, char *value, ArrayBuildState *astate, bool *foundAO, bool *aovalue) { text *t; bool boolval; int intval; StringInfoData buf; Assert(astate); initStringInfo(&buf); if (pg_strcasecmp(SOPT_APPENDONLY, name) == 0) { if (!parse_bool(value, &boolval)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid bool value \"%s\" for storage option \"%s\"", value, name))); /* "appendonly" option is explicitly specified. */ if (foundAO != NULL) *foundAO = true; if (aovalue != NULL) *aovalue = boolval; /* * Record value of "appendonly" option as true always. Return * the value specified by user in aovalue. Setting * appendonly=true always in the array of datums enables us to * reuse default_reloptions() and * validateAppendOnlyRelOptions(). If validations are * successful, we keep the user specified value for * appendonly. */ appendStringInfo(&buf, "%s=%s", SOPT_APPENDONLY, "true"); } else if (pg_strcasecmp(SOPT_BLOCKSIZE, name) == 0) { if (!parse_int(value, &intval, 0 /* unit flags */, NULL /* hint message */)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid integer value \"%s\" for storage option \"%s\"", value, name))); appendStringInfo(&buf, "%s=%d", SOPT_BLOCKSIZE, intval); } else if (pg_strcasecmp(SOPT_COMPTYPE, name) == 0) { appendStringInfo(&buf, "%s=%s", SOPT_COMPTYPE, value); } else if (pg_strcasecmp(SOPT_COMPLEVEL, name) == 0) { if (!parse_int(value, &intval, 0 /* unit flags */, NULL /* hint message */)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid integer value \"%s\" for storage option \"%s\"", value, name))); appendStringInfo(&buf, "%s=%d", SOPT_COMPLEVEL, intval); } else if (pg_strcasecmp(SOPT_CHECKSUM, name) == 0) { if (!parse_bool(value, &boolval)) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid bool value \"%s\" for storage option \"%s\"", value, name))); appendStringInfo(&buf, "%s=%s", SOPT_CHECKSUM, boolval ? "true" : "false"); } else if (pg_strcasecmp(SOPT_ORIENTATION, name) == 0) { if ((pg_strcasecmp(value, "row") != 0) && (pg_strcasecmp(value, "column") != 0)) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid value \"%s\" for storage option \"%s\"", value, name))); } appendStringInfo(&buf, "%s=%s", SOPT_ORIENTATION, value); } else { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid storage option \"%s\"", name))); } t = cstring_to_text(buf.data); accumArrayResult(astate, PointerGetDatum(t), /* disnull */ false, TEXTOID, CurrentMemoryContext); pfree(t); pfree(buf.data); }
static int factor_loadcol (void *p_consys, int i, int *rndx, double *coeff) /* This routine is used by luf_decomp to load columns of the basis into its internal data structure. The requirements are that it load rndx[] and coeff[] with the row indices and coefficients, respectively, of column i of the basis, returning the number of coefficients. Here, we need to look up the index j of the variable that actually occupies basis position i, retrieve the column, and load it into rndx and coeff. Parameters: p_consys: a consys_struct i: basis index rndx: (o) row indices i of coefficients a<ij> coeff: (o) coefficients a<ij> Returns: number of coefficients, or -1 in the event of an error. */ { int j,vecndx,pkndx ; double aij ; pkvec_struct *aj ; consys_struct *consys ; const char *rtnnme = "factor_loadcol" ; # ifdef DYLP_PARANOIA if (p_consys == NULL) { errmsg(2,rtnnme,"consys") ; return (-1) ; } if (rndx == NULL) { errmsg(2,rtnnme,"row index vector") ; return (-1) ; } if (coeff == NULL) { errmsg(2,rtnnme,"coefficient") ; return (-1) ; } # endif consys = (consys_struct *) p_consys ; aj = pkvec_new(consys->maxcollen) ; /* Retrieve the column ... */ j = dy_basis[i] ; if (consys_getcol_pk(consys,j,&aj) == FALSE) { errmsg(112,rtnnme,dy_sys->nme,"retrieve","column", consys_nme(dy_sys,'v',j,FALSE,NULL),j) ; if (aj != NULL) pkvec_free(aj) ; return (-1) ; } /* ... and load it into the return vectors rndx and coeff. */ vecndx = 1 ; for (pkndx = 0 ; pkndx < aj->cnt ; pkndx++) { aij = aj->coeffs[pkndx].val ; if (aij != 0.0) { rndx[vecndx] = aj->coeffs[pkndx].ndx ; coeff[vecndx] = aij ; vecndx++ ; } } /* Clean up and return. */ pkvec_free(aj) ; return (vecndx-1) ; }
/* * Insert a tuple to the new relation. This has to track heap_insert * and its subsidiary functions! * * t_self of the tuple is set to the new TID of the tuple. If t_ctid of the * tuple is invalid on entry, it's replaced with the new TID as well (in * the inserted data only, not in the caller's copy). */ static void raw_heap_insert(RewriteState state, HeapTuple tup) { Page page = state->rs_buffer; Size pageFreeSpace, saveFreeSpace; Size len; OffsetNumber newoff; HeapTuple heaptup; /* * If the new tuple is too big for storage or contains already toasted * out-of-line attributes from some other relation, invoke the toaster. * * Note: below this point, heaptup is the data we actually intend to store * into the relation; tup is the caller's original untoasted data. */ if (state->rs_new_rel->rd_rel->relkind == RELKIND_TOASTVALUE) { /* toast table entries should never be recursively toasted */ Assert(!HeapTupleHasExternal(tup)); heaptup = tup; } else if (HeapTupleHasExternal(tup) || tup->t_len > TOAST_TUPLE_THRESHOLD) heaptup = toast_insert_or_update(state->rs_new_rel, tup, NULL, HEAP_INSERT_SKIP_FSM | (state->rs_use_wal ? 0 : HEAP_INSERT_SKIP_WAL)); else heaptup = tup; len = MAXALIGN(heaptup->t_len); /* be conservative */ /* * If we're gonna fail for oversize tuple, do it right away */ if (len > MaxHeapTupleSize) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("row is too big: size %lu, maximum size %lu", (unsigned long) len, (unsigned long) MaxHeapTupleSize))); /* Compute desired extra freespace due to fillfactor option */ saveFreeSpace = RelationGetTargetPageFreeSpace(state->rs_new_rel, HEAP_DEFAULT_FILLFACTOR); /* Now we can check to see if there's enough free space already. */ if (state->rs_buffer_valid) { pageFreeSpace = PageGetHeapFreeSpace(page); if (len + saveFreeSpace > pageFreeSpace) { /* Doesn't fit, so write out the existing page */ /* XLOG stuff */ if (state->rs_use_wal) log_newpage(&state->rs_new_rel->rd_node, MAIN_FORKNUM, state->rs_blockno, page, true); /* * Now write the page. We say isTemp = true even if it's not a * temp table, because there's no need for smgr to schedule an * fsync for this write; we'll do it ourselves in * end_heap_rewrite. */ RelationOpenSmgr(state->rs_new_rel); PageSetChecksumInplace(page, state->rs_blockno); smgrextend(state->rs_new_rel->rd_smgr, MAIN_FORKNUM, state->rs_blockno, (char *) page, true); state->rs_blockno++; state->rs_buffer_valid = false; } } if (!state->rs_buffer_valid) { /* Initialize a new empty page */ PageInit(page, BLCKSZ, 0); state->rs_buffer_valid = true; } /* And now we can insert the tuple into the page */ newoff = PageAddItem(page, (Item) heaptup->t_data, heaptup->t_len, InvalidOffsetNumber, false, true); if (newoff == InvalidOffsetNumber) elog(ERROR, "failed to add tuple"); /* Update caller's t_self to the actual position where it was stored */ ItemPointerSet(&(tup->t_self), state->rs_blockno, newoff); /* * Insert the correct position into CTID of the stored tuple, too, if the * caller didn't supply a valid CTID. */ if (!ItemPointerIsValid(&tup->t_data->t_ctid)) { ItemId newitemid; HeapTupleHeader onpage_tup; newitemid = PageGetItemId(page, newoff); onpage_tup = (HeapTupleHeader) PageGetItem(page, newitemid); onpage_tup->t_ctid = tup->t_self; } /* If heaptup is a private copy, release it. */ if (heaptup != tup) heap_freetuple(heaptup); }
Datum internal_kmeans_agg_centroid_trans(PG_FUNCTION_ARGS) { ArrayType *array = NULL; ArrayType *cent_array = NULL; int32 dimension; int32 num_of_centroids; int32 centroid_index; bool rebuild_array = false; int32 expected_array_len; float8 *c_array = NULL; cent_array = PG_GETARG_ARRAYTYPE_P(verify_arg_nonnull(fcinfo, 1)); int array_dim = ARR_NDIM(cent_array); int *p_array_dim = ARR_DIMS(cent_array); int array_length = ArrayGetNItems(array_dim, p_array_dim); float8* c_cent_array = (float8 *)ARR_DATA_PTR(cent_array); dimension = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 2)); num_of_centroids = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 3)); centroid_index = PG_GETARG_INT32(verify_arg_nonnull(fcinfo, 4)); expected_array_len = num_of_centroids*dimension; if (dimension < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid dimension:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension))); } if (array_length != dimension) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Inconsistent Dimension. " "Expected:%d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), dimension, array_length))); } if (num_of_centroids < 1) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid num_of_centroids:%d", format_procedure(fcinfo->flinfo->fn_oid), num_of_centroids))); } if (centroid_index < 1 || centroid_index>num_of_centroids) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid centroid_index:%d", format_procedure(fcinfo->flinfo->fn_oid), centroid_index))); } if (PG_ARGISNULL(0)) { c_array = palloc0(expected_array_len*sizeof(float8)); rebuild_array = true; } else { if (fcinfo->context && IsA(fcinfo->context, AggState)) array = PG_GETARG_ARRAYTYPE_P(0); else array = PG_GETARG_ARRAYTYPE_P_COPY(0); array_dim = ARR_NDIM(array); p_array_dim = ARR_DIMS(array); array_length = ArrayGetNItems(array_dim, p_array_dim); if (array_length != expected_array_len) { ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("function \"%s\", Invalid array length. " "Expected: %d, Actual:%d", format_procedure(fcinfo->flinfo->fn_oid), expected_array_len, array_length))); } c_array = (float8 *)ARR_DATA_PTR(array); } float8 * data_ptr = c_array+(centroid_index-1)*dimension; for(int index=0; index<dimension; index++) { data_ptr[index] = c_cent_array[index]; } if (rebuild_array) { /* construct a new array to keep the aggr states. */ array = construct_array( (Datum *)c_array, expected_array_len, FLOAT8OID, sizeof(float8), true, 'd' ); } PG_RETURN_ARRAYTYPE_P(array); }
static void PersistentFilespace_GetPaths(FilespaceDirEntry filespaceDirEntry, char **primaryFilespaceLocation, char **mirrorFilespaceLocation) { int16 primaryDbId; char *primaryBlankPadded = NULL; char *mirrorBlankPadded = NULL; /* * The persistent_filespace_node_table contains the paths for both the * primary and mirror nodes, and the table is the same on both sides of * the mirror. When it was first created the primary put its location * first, but we don't know if we were the primary when it was created or * not. To determine which path corresponds to this node we compare our * dbid to the one stored in the table. */ primaryDbId = GpIdentity.dbid; if (filespaceDirEntry->dbId1 == primaryDbId) { /* dbid == dbid1 */ primaryBlankPadded = filespaceDirEntry->locationBlankPadded1; mirrorBlankPadded = filespaceDirEntry->locationBlankPadded2; } else if (filespaceDirEntry->dbId2 == primaryDbId) { /* dbid == dbid2 */ primaryBlankPadded = filespaceDirEntry->locationBlankPadded2; mirrorBlankPadded = filespaceDirEntry->locationBlankPadded1; } else { /* * The dbid check above does not work for the Master Node during * initial startup, because the master doesn't yet know its own dbid. * To handle this we special case for the master node the master * always considers the first entry as the correct location. * * Note: This design may need to be reconsidered to handle standby * masters! */ PrimaryMirrorMode mode; getPrimaryMirrorStatusCodes(&mode, NULL, NULL, NULL); if (mode == PMModeMaster) { /* Master node */ primaryBlankPadded = filespaceDirEntry->locationBlankPadded1; mirrorBlankPadded = filespaceDirEntry->locationBlankPadded2; } else { /* * Current dbid matches neither dbid in table and was not started * as a master node. */ ereport(FATAL, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("Unable to determine dbid for filespace lookup"))); } } /* These should both have been populated by one of the cases above */ Assert(primaryBlankPadded); Assert(mirrorBlankPadded); PersistentFilespace_ConvertBlankPaddedLocation( primaryFilespaceLocation, primaryBlankPadded, /* isPrimary */ true); PersistentFilespace_ConvertBlankPaddedLocation( mirrorFilespaceLocation, mirrorBlankPadded, /* isPrimary */ false); }
/* * Adjust dependency record(s) to point to a different object of the same type * * classId/objectId specify the referencing object. * refClassId/oldRefObjectId specify the old referenced object. * newRefObjectId is the new referenced object (must be of class refClassId). * * Note the lack of objsubid parameters. If there are subobject references * they will all be readjusted. * * Returns the number of records updated. */ long changeDependencyFor(Oid classId, Oid objectId, Oid refClassId, Oid oldRefObjectId, Oid newRefObjectId) { long count = 0; Relation depRel; ScanKeyData key[2]; SysScanDesc scan; HeapTuple tup; ObjectAddress objAddr; bool newIsPinned; depRel = heap_open(DependRelationId, RowExclusiveLock); /* * If oldRefObjectId is pinned, there won't be any dependency entries on * it --- we can't cope in that case. (This isn't really worth expending * code to fix, in current usage; it just means you can't rename stuff out * of pg_catalog, which would likely be a bad move anyway.) */ objAddr.classId = refClassId; objAddr.objectId = oldRefObjectId; objAddr.objectSubId = 0; if (isObjectPinned(&objAddr, depRel)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("cannot remove dependency on %s because it is a system object", getObjectDescription(&objAddr)))); /* * We can handle adding a dependency on something pinned, though, since * that just means deleting the dependency entry. */ objAddr.objectId = newRefObjectId; newIsPinned = isObjectPinned(&objAddr, depRel); /* Now search for dependency records */ ScanKeyInit(&key[0], Anum_pg_depend_classid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(classId)); ScanKeyInit(&key[1], Anum_pg_depend_objid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(objectId)); scan = systable_beginscan(depRel, DependDependerIndexId, true, SnapshotNow, 2, key); while (HeapTupleIsValid((tup = systable_getnext(scan)))) { Form_pg_depend depform = (Form_pg_depend) GETSTRUCT(tup); if (depform->refclassid == refClassId && depform->refobjid == oldRefObjectId) { if (newIsPinned) simple_heap_delete(depRel, &tup->t_self); else { /* make a modifiable copy */ tup = heap_copytuple(tup); depform = (Form_pg_depend) GETSTRUCT(tup); depform->refobjid = newRefObjectId; simple_heap_update(depRel, &tup->t_self, tup); CatalogUpdateIndexes(depRel, tup); heap_freetuple(tup); } count++; } } systable_endscan(scan); heap_close(depRel, RowExclusiveLock); return count; }
dyret_enum dy_factor (flags *calcflgs) /* This routine orchestrates the LU factorisation of the basis. The glpk routines do the grunt work. This routine provides the intelligence. If inv_decomp aborts the attempt to factor due to numerical instability, we tighten the pivot selection parameters one notch and try again, giving up only when no further increase is possible. The sequence of values for the pivot selection parameters are defined in a table at the top of this file. If inv_decomp aborts the attempt to factor because the basis is singular, we correct the basis with adjust_basis and take another run at factoring. In the event that the basis is successfully patched, we have serious work to do. See the comments with adjust_therest for further information. If the user has for some reason disabled basis patching, we return dyrSINGULAR. inv_decomp (actually, luf_decomp) is self-expanding --- if more space is needed to hold the factorization, the expansion is handled internally. dylp uses ladEXPAND to force basis expansion after a pivot fails due to lack of space. In glpk, inv_update will set instructions in the basis structure and luf_decomp will handle the expansion, so ladEXPAND is redundant. No action need be taken in this routine. It's also not possible to tell if the basis has been expanded, so ladEXPAND is not set on output. Parameters: calcflgs: (i) ladPRIMALS indicates the primal variables should be recalculated after factoring the basis. ladDUALS indicates the dual variables should be recalculated after factoring the basis. ladEXPAND indicates that the basis should be expanded prior to refactoring. (o) flags are set to indicate if the corresponding variables have been recalculated. Returns: dyrOK if the basis is factored without incident dyrPATCHED if the basis was singular and has been repaired dyrSINGULAR if the basis was singular and has not been repaired dyrNUMERIC if factoring failed for the strictest pivoting regimen dyrFATAL for other fatal errors NOTE: glpinv/glpluf will crash and burn if they encounter what they consider to be a fatal error, rather than returning a fatal error code. This needs to be addressed at some point. In particular, failure to expand the basis, failure to load the basis from the constraint system, and various parameter errors fall into this category. */ { int retval,patchcnt ; bool try_again,patched ; dyret_enum retcode ; patch_struct *patches ; const char *rtnnme = "dy_factor" ; #ifdef DYLP_PARANOIA if (dy_sys == NULL) { errmsg(2,rtnnme,"dy_sys") ; return (dyrFATAL) ; } if (dy_basis == NULL) { errmsg(2,rtnnme,"basis") ; return (dyrFATAL) ; } #endif # ifdef DYLP_STATISTICS if (dy_stats != NULL) { int pivcnt ; pivcnt = dy_lp->tot.pivs-dy_stats->factor.prevpiv ; dy_stats->factor.avgpivs = dy_stats->factor.avgpivs*dy_stats->factor.cnt ; dy_stats->factor.avgpivs += pivcnt ; dy_stats->factor.cnt++ ; dy_stats->factor.avgpivs /= dy_stats->factor.cnt ; if (pivcnt > dy_stats->factor.maxpivs) dy_stats->factor.maxpivs = pivcnt ; dy_stats->factor.prevpiv = dy_lp->tot.pivs ; } # endif retcode = dyrINV ; patchcnt = 0 ; patches = NULL ; /* Call luf_adjustsize to set the actual size of the basis. If the allocated capacity is too small, it will be expanded. */ luf_adjustsize() ; /* Open a loop for factorisation attempts. We'll persist in the face of numerical stability problems as long as there's room to tighten the pivot selection. At present, glpinv/glpluf will crash and burn if they encounter fatal problems. The basis load is implicit --- the routine factor_loadcol is called from luf_decomp to load up the coefficients. */ try_again = TRUE ; patched = FALSE ; while (try_again) { retval = inv_decomp(luf_basis,dy_sys,factor_loadcol) ; # ifndef DYLP_NDEBUG if ((retval == 0 && dy_opts->print.basis >= 4) || (retval > 0 && dy_opts->print.basis >= 2)) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n (%s)%d: factored with %s, basis stability %g.", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters, dy_prtpivparms(-1),luf_basis->min_vrratio) ; } # endif /* Deal with the result. A return code of 0 means there were no difficulties; 1 says the basis was singular and had to be patched before the factorisation could be completed. Either is success, and we're done. */ switch (retval) { case 0: { try_again = FALSE ; retcode = dyrOK ; break ; } /* Alas, the failures. If the problem is a singular basis (retval = 1), fix up the basis structures as indicated in the luf_basis structure and try again to factor the basis, unless the user has forbidden it. If the problem is numerical instability (retval = 2) try to make the pivot selection more stringent, and keep trying until we can try no more, at which point we'll return numeric instability to the caller. What's left is fatal confusion; pass the buck back to the caller. */ case 1: { if (dy_opts->patch == FALSE) { errmsg(308,rtnnme,dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters,dy_prtdyret(dyrSINGULAR)) ; clrflg(*calcflgs,ladPRIMALS|ladDUALS) ; return (dyrSINGULAR) ; } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n (%s)%d: attempting to patch singular basis.", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters) ; } # endif adjust_basis(&patchcnt,&patches) ; patched = TRUE ; break ; } case 2: { retcode = dyrNUMERIC ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n (%s)%d: factor failed at %s, numerical instability,", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters, dy_prtpivparms(-1)) ; dyio_outfmt(dy_logchn,dy_gtxecho," max = %g, gro = %g.", luf_basis->luf->big_v,luf_basis->luf->max_gro) ; } # endif if (dy_setpivparms(+1,0) == FALSE) { errmsg(307,rtnnme,dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters,dy_prtpivparms(-1)) ; return (retcode) ; } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho,"\n\ttrying again with %s.", dy_prtpivparms(-1)) ; } # endif break ; } default: { errmsg(7,rtnnme,__LINE__,"inv_decomp return code",retval) ; return (dyrFATAL) ; } } } /* If we reach here, we managed to factor the basis. Reset the count of pivots since the last refactor. If the basis was patched, we have some serious cleanup to do, so call adjust_therest to deal with the details. Otherwise, turn to the requests to calculate values for the primal and/or dual variables. */ dy_lp->basis.etas = 0 ; if (patched == TRUE) { retcode = adjust_therest(patchcnt,patches) ; FREE(patches) ; if (retcode == dyrFATAL) { errmsg(306,rtnnme,dy_sys->nme,dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters) ; return (dyrFATAL) ; } # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 1) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t[%s]: compensated for basis correction.", dy_sys->nme) ; } # endif if (!(dy_lp->phase == dyINIT)) { setflg(*calcflgs,ladPRIMALS|ladDUALS) ; if (retcode == dyrLOSTDFEAS) setflg(*calcflgs,ladDUALFEAS) ; } retcode = dyrPATCHED ; } else { if (flgon(*calcflgs,ladPRIMALS)) { if (dy_calcprimals() == FALSE) { clrflg(*calcflgs,ladPRIMALS) ; return (dyrFATAL) ; } } if (flgon(*calcflgs,ladDUALS)) dy_calcduals() ; } return (retcode) ; }
void scanXDBinputText(xformDatabase* xdb, FILE *inf, FILE *outf, abrMkAtomProc mkAtom, void *atomstuff, char *cch) { transformData* xform = NULL; char *s = NULL; char saynull[] = "NULL:identity transformation:"; while(readRecord(inf, XFworkBuf, MAX_XF_REC_LEN) >= 0) { if (isAtom(XFworkBuf) || isHet(XFworkBuf)) { if (! xform) { /* make someplace to hang these atoms */ xform = newTransformation(saynull); appendTransformation(xdb, xform); } if (! xform) { errmsg("could not create Identity transformation - Atom skipped"); } else if (isPseudoAtom(XFworkBuf)) { /* ignore pseudo atoms */ } else { appendAtomRec(xform, XFworkBuf, mkAtom, atomstuff); } } else { s = XFworkBuf + strspn(XFworkBuf, " \t\n\r"); if (!strncasecmp(s, "BONDROT",7) || !strncasecmp(s, "ROT", 3) || !strncasecmp(s, "TRANS",5) || !strncasecmp(s, "SAVE", 4) || (s[0] == '(') || !strncasecmp(s, "RESTORE",7) || (s[0] == ')') ) { xform = newTransformation(s); appendTransformation(xdb, xform); } else if (!strncasecmp(s, "GO", 2)) { addGoToRecord(xdb, s); } else if (!strncasecmp(s, "COS", 3) || !strncasecmp(s, "POLY", 4) || !strncasecmp(s, "CONST", 5) ) { if (xform) { appendBiasFunction(xform, s); } else { warn("no transformation to attach bias function:"); warn(s); } } else if (s[0] == '#' || s[0] == '\0') { /* comments are ok - we do nothing */ } else if (s[0] == '@') { /* include file */ FILE *if2 = NULL; if2 = fopen(s+1, "r"); if (if2) { /* recursive call */ fprintf(outf, "%s%s\n", cch, s); scanXDBinputText(xdb, if2, outf, mkAtom, atomstuff, cch); fclose(if2); } else { warn("could not open include file:"); warn(s+1); } } else { warn("unknown record type:"); warn(s); } } } }
dyret_enum dy_pivot (int xipos, double abarij, double maxabarj) /* This routine handles a single pivot. It first checks that the pivot element satisfies a stability test, then calls inv_update to pivot the basis. We can still run into trouble, however, if the pivot results in a singular or near-singular basis. NOTE: There is an implicit argument here that's not immediately obvious. inv_update gets the entering column from a cached result set with the most recent call to inv_ftran(*,1) (dy_ftran(*,true), if you prefer). The underlying assumption is that this is readily available from when we ftran'd the entering column to find the leaving variable. Parameters: xipos: the basis position of the entering variable abarij: the pivot element (only the absolute value is used) maxabarj: for a primal pivot, max{i} |abar<i,j>|, for a dual pivot, max{j} |abar<i,j>| Returns: dyrOK: the pivot was accomplished without incident (inv_update) dyrMADPIV: the pivot element abar<i,j> was rejected as numerically unstable (dy_chkpiv) dyrSINGULAR: the pivot attempt resulted in a structurally singular basis (i.e., some diagonal element is zero) (inv_update) dyrNUMERIC: the pivot attempt resulted in a numerically singular (unstable) basis (i.e, some diagonal element is too small compared to other elements in the associated row and column) (inv_update) dyrBSPACE: glpinv/glpluf ran out of space for the basis representation (inv_update) dyrFATAL: internal confusion */ { int retval ; double ratio ; dyret_enum retcode ; const char *rtnnme = "dy_pivot" ; /* Check that the pivot element meets the current criterion for numerical stability. Arguably this should have been checked by the caller, but that's no excuse for not doing it now. */ ratio = dy_chkpiv(abarij,maxabarj) ; if (ratio < 1.0) { # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 3) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n %s(%d) pivot aborted; est. pivot stability %g.", dy_prtlpphase(dy_lp->phase,TRUE), dy_lp->tot.iters,rtnnme,ratio) ; } # endif return (dyrMADPIV) ; } /* Make the call to inv_update, then recode the result. */ retval = inv_update(luf_basis,xipos) ; # ifndef DYLP_NDEBUG if ((retval == 0 && dy_opts->print.basis >= 5) || (retval > 0 && dy_opts->print.basis >= 3)) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n %s(%d) estimated pivot stability %g; ", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters,ratio) ; dyio_outfmt(dy_logchn,dy_gtxecho,"measured pivot stability %g.", luf_basis->min_vrratio) ; } # endif switch (retval) { case 0: { retcode = dyrOK ; break ; } case 1: { retcode = dyrSINGULAR ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n %s(%d) singular basis (structural) after pivot.", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters) ; } # endif break ; } case 2: { retcode = dyrNUMERIC ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n %s(%d) singular basis (numeric) after pivot.", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters) ; } # endif break ; } case 3: case 4: { retcode = dyrBSPACE ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho,"\n %s(%d) out of space (%s)", dy_prtlpphase(dy_lp->phase,TRUE),dy_lp->tot.iters, (retval == 3)?"eta matrix limit":"sparse vector area") ; } # endif break ; } default: { errmsg(1,rtnnme,__LINE__) ; retcode = dyrFATAL ; break ; } } return (retcode) ; }
/* * CREATE CONVERSION */ void CreateConversionCommand(CreateConversionStmt *stmt) { Oid namespaceId; char *conversion_name; AclResult aclresult; int from_encoding; int to_encoding; Oid funcoid; const char *from_encoding_name = stmt->for_encoding_name; const char *to_encoding_name = stmt->to_encoding_name; List *func_name = stmt->func_name; static Oid funcargs[] = {INT4OID, INT4OID, CSTRINGOID, INTERNALOID, INT4OID}; char result[1]; /* Convert list of names to a name and namespace */ namespaceId = QualifiedNameGetCreationNamespace(stmt->conversion_name, &conversion_name); /* Check we have creation rights in target namespace */ aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_CREATE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_NAMESPACE, get_namespace_name(namespaceId)); /* Check the encoding names */ from_encoding = pg_char_to_encoding(from_encoding_name); if (from_encoding < 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("source encoding \"%s\" does not exist", from_encoding_name))); to_encoding = pg_char_to_encoding(to_encoding_name); if (to_encoding < 0) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("destination encoding \"%s\" does not exist", to_encoding_name))); /* * Check the existence of the conversion function. Function name could be * a qualified name. */ funcoid = LookupFuncName(func_name, sizeof(funcargs) / sizeof(Oid), funcargs, false); /* Check it returns VOID, else it's probably the wrong function */ if (get_func_rettype(funcoid) != VOIDOID) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), errmsg("encoding conversion function %s must return type \"void\"", NameListToString(func_name)))); /* Check we have EXECUTE rights for the function */ aclresult = pg_proc_aclcheck(funcoid, GetUserId(), ACL_EXECUTE); if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, ACL_KIND_PROC, NameListToString(func_name)); /* * Check that the conversion function is suitable for the requested source * and target encodings. We do that by calling the function with an empty * string; the conversion function should throw an error if it can't * perform the requested conversion. */ OidFunctionCall5(funcoid, Int32GetDatum(from_encoding), Int32GetDatum(to_encoding), CStringGetDatum(""), CStringGetDatum(result), Int32GetDatum(0)); /* * All seem ok, go ahead (possible failure would be a duplicate conversion * name) */ ConversionCreate(conversion_name, namespaceId, GetUserId(), from_encoding, to_encoding, funcoid, stmt->def); }
bool dy_setpivparms (int curdelta, int mindelta) /* This routine exists to allow other parts of the lp code to adjust the pivot regimen used when the basis is factored. curdelta is the change in the current pivot level, mindelta the change in the minimum pivot level. A positive delta increases (tightens) the tolerances by delta steps, and a negative delta lowers (loosens) them. If either delta is 0, there's no change. A large positive or negative value slams the tolerance to the appropriate extreme. Parameters: curdelta: change to the current pivot level mindelta: change to the minimum pivot level Returns: TRUE if any change actually occurred, FALSE if we were already at the relevant limit(s) (BE CAREFUL interpreting the return value if you're changing both at once) */ { bool minretval,curretval ; # ifdef DYLP_PARANOIA const char *rtnnme = "dy_setpivparms" ; if (luf_basis == NULL) { errmsg(2,rtnnme,"luf_basis") ; return (FALSE) ; } # endif minretval = FALSE ; curretval = FALSE ; /* Adjust the minimum pivot level first. This may imply an adjustment in the current pivot level. */ if (mindelta != 0) { if ((minpivlevel <= 0 && mindelta < 0) || (minpivlevel >= MAX_PIVLEVEL && mindelta > 0)) { # ifndef DYLP_NDEBUG if ((dy_opts->print.basis >= 3) || (dy_opts->print.basis >= 2 && mindelta > 0)) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t min. pivot ratio unchanged at %s (%d)", dy_prtpivparms(minpivlevel),minpivlevel) ; } # endif } else { minretval = TRUE ; minpivlevel += mindelta ; if (minpivlevel < 0) minpivlevel = 0 ; else if (minpivlevel > MAX_PIVLEVEL) minpivlevel = MAX_PIVLEVEL ; if (pivlevel < minpivlevel) curdelta = maxx(curdelta,(minpivlevel-pivlevel)) ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t setting min. pivot ratio to %s (%d)", dy_prtpivparms(minpivlevel),minpivlevel) ; } # endif } } /* Adjust the current pivot level. */ if (curdelta != 0) { if ((pivlevel <= minpivlevel && curdelta < 0) || (pivlevel >= MAX_PIVLEVEL && curdelta > 0)) { # ifndef DYLP_NDEBUG if ((dy_opts->print.basis >= 3) || (dy_opts->print.basis >= 2 && mindelta > 0)) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t cur. pivot ratio unchanged at %s (%d)", dy_prtpivparms(-1),pivlevel) ; } # endif } else { curretval = TRUE ; pivlevel += curdelta ; if (pivlevel < minpivlevel) pivlevel = minpivlevel ; else if (pivlevel > MAX_PIVLEVEL) pivlevel = MAX_PIVLEVEL ; luf_basis->luf->piv_tol = pivtols[pivlevel].stable ; luf_basis->luf->piv_lim = pivtols[pivlevel].look ; # ifndef DYLP_NDEBUG if (dy_opts->print.basis >= 2) { dyio_outfmt(dy_logchn,dy_gtxecho, "\n\t setting cur. pivot ratio to %s (%d)", dy_prtpivparms(-1),pivlevel) ; } # endif } } if (curretval == FALSE && minretval == FALSE) return (FALSE) ; else return (TRUE) ; }
/* * CREATE TEXT SEARCH PARSER */ ObjectAddress DefineTSParser(List *names, List *parameters) { char *prsname; ListCell *pl; Relation prsRel; HeapTuple tup; Datum values[Natts_pg_ts_parser]; bool nulls[Natts_pg_ts_parser]; NameData pname; Oid prsOid; Oid namespaceoid; ObjectAddress address; if (!superuser()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("must be superuser to create text search parsers"))); /* Convert list of names to a name and namespace */ namespaceoid = QualifiedNameGetCreationNamespace(names, &prsname); /* initialize tuple fields with name/namespace */ memset(values, 0, sizeof(values)); memset(nulls, false, sizeof(nulls)); namestrcpy(&pname, prsname); values[Anum_pg_ts_parser_prsname - 1] = NameGetDatum(&pname); values[Anum_pg_ts_parser_prsnamespace - 1] = ObjectIdGetDatum(namespaceoid); /* * loop over the definition list and extract the information we need. */ foreach(pl, parameters) { DefElem *defel = (DefElem *) lfirst(pl); if (pg_strcasecmp(defel->defname, "start") == 0) { values[Anum_pg_ts_parser_prsstart - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsstart); } else if (pg_strcasecmp(defel->defname, "gettoken") == 0) { values[Anum_pg_ts_parser_prstoken - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prstoken); } else if (pg_strcasecmp(defel->defname, "end") == 0) { values[Anum_pg_ts_parser_prsend - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsend); } else if (pg_strcasecmp(defel->defname, "headline") == 0) { values[Anum_pg_ts_parser_prsheadline - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prsheadline); } else if (pg_strcasecmp(defel->defname, "lextypes") == 0) { values[Anum_pg_ts_parser_prslextype - 1] = get_ts_parser_func(defel, Anum_pg_ts_parser_prslextype); } else ereport(ERROR, (errcode(ERRCODE_SYNTAX_ERROR), errmsg("text search parser parameter \"%s\" not recognized", defel->defname))); }
/* * initSuffixTree - create suffix tree from file. Function converts * UTF8-encoded file into current encoding. */ static SuffixChar * initSuffixTree(char *filename) { SuffixChar *volatile rootSuffixTree = NULL; MemoryContext ccxt = CurrentMemoryContext; tsearch_readline_state trst; volatile bool skip; filename = get_tsearch_config_filename(filename, "rules"); if (!tsearch_readline_begin(&trst, filename)) ereport(ERROR, (errcode(ERRCODE_CONFIG_FILE_ERROR), errmsg("could not open unaccent file \"%s\": %m", filename))); do { /* * pg_do_encoding_conversion() (called by tsearch_readline()) will * emit exception if it finds untranslatable characters in current * locale. We just skip such lines, continuing with the next. */ skip = true; PG_TRY(); { char *line; while ((line = tsearch_readline(&trst)) != NULL) { /* * The format of each line must be "src trg" where src and trg * are sequences of one or more non-whitespace characters, * separated by whitespace. Whitespace at start or end of * line is ignored. */ int state; char *ptr; char *src = NULL; char *trg = NULL; int ptrlen; int srclen = 0; int trglen = 0; state = 0; for (ptr = line; *ptr; ptr += ptrlen) { ptrlen = pg_mblen(ptr); /* ignore whitespace, but end src or trg */ if (t_isspace(ptr)) { if (state == 1) state = 2; else if (state == 3) state = 4; continue; } switch (state) { case 0: /* start of src */ src = ptr; srclen = ptrlen; state = 1; break; case 1: /* continue src */ srclen += ptrlen; break; case 2: /* start of trg */ trg = ptr; trglen = ptrlen; state = 3; break; case 3: /* continue trg */ trglen += ptrlen; break; default: /* bogus line format */ state = -1; break; } } if (state >= 3) rootSuffixTree = placeChar(rootSuffixTree, (unsigned char *) src, srclen, trg, trglen); pfree(line); } skip = false; } PG_CATCH(); { ErrorData *errdata; MemoryContext ecxt; ecxt = MemoryContextSwitchTo(ccxt); errdata = CopyErrorData(); if (errdata->sqlerrcode == ERRCODE_UNTRANSLATABLE_CHARACTER) { FlushErrorState(); } else { MemoryContextSwitchTo(ecxt); PG_RE_THROW(); } } PG_END_TRY(); } while (skip); tsearch_readline_end(&trst); return rootSuffixTree; }