10000 Rewrite aqo_cardinality_error in C. · postgrespro/aqo@3286434 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3286434

Browse files
danolivoAlena Rybakina
authored and
Alena Rybakina
committed
Rewrite aqo_cardinality_error in C.
One more step towards true relocatability.
1 parent 1f2144e commit 3286434

File tree

2 files changed

+95
-38
lines changed

2 files changed

+95
-38
lines changed

aqo--1.4--1.5.sql

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -167,44 +167,8 @@ COMMENT ON FUNCTION aqo_cleanup() IS
167167
--
168168
CREATE OR REPLACE FUNCTION aqo_cardinality_error(controlled boolean)
169169
RETURNS TABLE(num bigint, id bigint, fshash bigint, error float, nexecs bigint)
170-
AS $$
171-
BEGIN
172-
IF (controlled) THEN
173-
RETURN QUERY
174-
SELECT
175-
row_number() OVER (ORDER BY (cerror, query_id, fs_hash) DESC) AS nn,
176-
query_id, fs_hash, cerror, execs
177-
FROM (
178-
SELECT
179-
aq.queryid AS query_id,
180-
aq.fs AS fs_hash,
181-
cardinality_error_with_aqo[array_length(cardinality_error_with_aqo, 1)] AS cerror,
182-
executions_with_aqo AS execs
183-
FROM aqo_queries aq JOIN aqo_query_stat aqs
184-
ON aq.queryid = aqs.queryid
185-
WHERE TRUE = ANY (SELECT unnest(cardinality_error_with_aqo) IS NOT NULL)
186-
) AS q1
187-
ORDER BY nn ASC;
188-
ELSE
189-
RETURN QUERY
190-
SELECT
191-
row_number() OVER (ORDER BY (cerror, query_id, fs_hash) DESC) AS nn,
192-
query_id, fs_hash, cerror, execs
193-
FROM (
194-
SELECT
195-
aq.queryid AS query_id,
196-
aq.fs AS fs_hash,
197-
(SELECT AVG(t) FROM unnest(cardinality_error_without_aqo) t) AS cerror,
198-
executions_without_aqo AS execs
199-
FROM aqo_queries aq JOIN aqo_query_stat aqs
200-
ON aq.queryid = aqs.queryid
201-
WHERE TRUE = ANY (SELECT unnest(cardinality_error_without_aqo) IS NOT NULL)
202-
) AS q1
203-
ORDER BY (nn) ASC;
204-
END IF;
205-
END;
206-
$$ LANGUAGE plpgsql;
207-
170+
AS 'MODULE_PATHNAME', 'aqo_cardinality_error'
171+
LANGUAGE C STRICT VOLATILE;
208172
COMMENT ON FUNCTION aqo_cardinality_error(boolean) IS
209173
'Get cardinality error of queries the last time they were executed. Order queries according to an error value.';
210174

storage.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ PG_FUNCTION_INFO_V1(aqo_queries_update);
102102
PG_FUNCTION_INFO_V1(aqo_reset);
103103
PG_FUNCTION_INFO_V1(aqo_cleanup);
104104
PG_FUNCTION_INFO_V1(aqo_drop_class);
105+
PG_FUNCTION_INFO_V1(aqo_cardinality_error);
105106

106107

107108
bool
@@ -2203,3 +2204,95 @@ aqo_drop_class(PG_FUNCTION_ARGS)
22032204

22042205
PG_RETURN_INT32(cnt);
22052206
}
2207+
2208+
typedef enum {
2209+
AQE_NN = 0, AQE_QUERYID, AQE_FS, AQE_CERROR, AQE_NEXECS, AQE_TOTAL_NCOLS
2210+
} ce_output_order;
2211+
2212+
/*
2213+
* Show cardinality error gathered on last execution.
2214+
* Skip entries with empty stat slots. XXX: is it possible?
2215+
*/
2216+
Datum
2217+
aqo_cardinality_error(PG_FUNCTION_ARGS)
2218+
{
2219+
bool controlled = PG_GETARG_BOOL(0);
2220+
ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
2221+
TupleDesc tupDesc;
2222+
MemoryContext per_query_ctx;
2223+
MemoryContext oldcontext;
2224+
Tuplestorestate *tupstore;
2225+
Datum values[AQE_TOTAL_NCOLS];
2226+
bool nulls[AQE_TOTAL_NCOLS];
2227+
HASH_SEQ_STATUS hash_seq;
2228+
QueriesEntry *qentry;
2229+
StatEntry *sentry;
2230+
int counter = 0;
2231+
2232+
/* check to see if caller supports us returning a tuplestore */
2233+
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
2234+
ereport(ERROR,
2235+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2236+
errmsg("set-valued function called in context that cannot accept a set")));
2237+
if (!(rsinfo->allowedModes & SFRM_Materialize))
2238+
ereport(ERROR,
2239+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2240+
errmsg("materialize mode required, but it is not allowed in this context")));
2241+
2242+
/* Switch into long-lived context to construct returned data structures */
2243+
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
2244+
oldcontext = MemoryContextSwitchTo(per_query_ctx);
2245+
2246+
/* Build a tuple descriptor for our result type */
2247+
if (get_call_result_type(fcinfo, NULL, &tupDesc) != TYPEFUNC_COMPOSITE)
2248+
elog(ERROR, "return type must be a row type");
2249+
Assert(tupDesc->natts == AQE_TOTAL_NCOLS);
2250+
2251+
tupstore = tuplestore_begin_heap(true, false, work_mem);
2252+
rsinfo->returnMode = SFRM_Materialize;
2253+
rsinfo->setResult = tupstore;
2254+
rsinfo->setDesc = tupDesc;
2255+
2256+
MemoryContextSwitchTo(oldcontext);
2257+
2258+
LWLockAcquire(&aqo_state->queries_lock, LW_SHARED);
2259+
LWLockAcquire(&aqo_state->stat_lock, LW_SHARED);
2260+
2261+
hash_seq_init(&hash_seq, queries_htab);
2262+
while ((qentry = hash_seq_search(&hash_seq)) != NULL)
2263+
{
2264+
bool found;
2265+
double *ce;
2266+
int64 nexecs;
2267+
int nvals;
2268+
2269+
memset(nulls, 0, AQE_TOTAL_NCOLS * sizeof(nulls[0]));
2270+
2271+
sentry = (StatEntry *) hash_search(stat_htab, &qentry->queryid,
2272+
HASH_FIND, &found);
2273+
if (!found)
2274+
/* Statistics not found by some reason. Just go further */
2275+
continue;
2276+
2277+
nvals = controlled ? sentry->cur_stat_slot_aqo : sentry->cur_stat_slot;
2278+
if (nvals == 0)
2279+
/* No one stat slot filled */
2280+
continue;
2281+
2282+
nexecs = controlled ? sentry->execs_with_aqo : sentry->execs_without_aqo;
2283+
ce = controlled ? sentry->est_error_aqo : sentry->est_error;
2284+
2285+
values[AQE_NN] = Int32GetDatum(counter++);
2286+
values[AQE_QUERYID] = Int64GetDatum(qentry->queryid);
2287+
values[AQE_FS] = Int64GetDatum(qentry->fs);
2288+
values[AQE_NEXECS] = Int64GetDatum(nexecs);
2289+
values[AQE_CERROR] = Float8GetDatum(ce[nvals - 1]);
2290+
tuplestore_putvalues(tupstore, tupDesc, values, nulls);
2291+
}
2292+
2293+
LWLockRelease(&aqo_state->stat_lock);
2294+
LWLockRelease(&aqo_state->queries_lock);
2295+
2296+
tuplestore_donestoring(tupstore);
2297+
return (Datum) 0;
2298+
}

0 commit comments

Comments
 (0)
0