La función manejadora TSM devuelve una estructura TsmRoutine asignada con palloc
que contiene punteros a las funciones de soporte descritas a continuación. La mayoría de
las funciones son obligatorias, pero algunas son opcionales y esos punteros pueden
ser NULL.
void
SampleScanGetSampleSize (PlannerInfo *root,
RelOptInfo *baserel,
List *paramexprs,
BlockNumber *pages,
double *tuples);
Esta función se llama durante la planificación. Debe estimar el número de
páginas de la relación que se leerán durante un escaneo de muestra, y el número de
tuplas que se seleccionarán en el escaneo. (Por ejemplo, estos podrían
determinarse estimando la fracción de muestreo y luego multiplicando
los números de baserel->pages y baserel->tuples
por ella, asegurándose de redondear los resultados a valores enteros).
La lista paramexprs contiene la(s) expresión(es) que son
parámetros de la cláusula TABLESAMPLE. Se recomienda
usar estimate_expression_value() para intentar reducir estas
expresiones a constantes, si sus valores son necesarios para fines de estimación;
pero la función debe proporcionar estimaciones de tamaño incluso si no se pueden
reducir, y no debe fallar incluso si los valores parecen inválidos
(recuerda que solo son estimaciones de lo que serán los valores en tiempo de ejecución).
Los parámetros pages and tuples son salidas.
void
InitSampleScan (SampleScanState *node,
int eflags);
Inicializa para la ejecución de un nodo de plan SampleScan.
Esto se llama durante el inicio del ejecutor.
Debe realizar cualquier inicialización necesaria antes de que pueda comenzar el procesamiento.
El nodo SampleScanState ya ha sido creado, pero
su campo tsm_state es NULL.
La función InitSampleScan puede asignar con palloc cualquier
dato de estado interno que necesite el método de muestreo y almacenar un puntero a
él en node->tsm_state.
La información sobre la tabla a escanear es accesible a través de otros campos
del nodo SampleScanState (pero ten en cuenta que el descriptor de
escaneo node->ss.ss_currentScanDesc aún no está configurado).
eflags contiene bits de bandera que describen el modo de
operación del ejecutor para este nodo de plan.
Cuando (eflags & EXEC_FLAG_EXPLAIN_ONLY) es true,
el escaneo no se realizará realmente, por lo que esta función solo debe hacer
lo mínimo requerido para que el estado del nodo sea válido para EXPLAIN
y EndSampleScan.
Esta función se puede omitir (establecer el puntero en NULL), en cuyo caso
BeginSampleScan debe realizar toda la inicialización requerida
por el método de muestreo.
void
BeginSampleScan (SampleScanState *node,
Datum *params,
int nparams,
uint32 seed);
Comienza la ejecución de un escaneo de muestra.
Esto se llama justo antes del primer intento de obtener una tupla, y
puede llamarse nuevamente si el escaneo necesita ser reiniciado.
La información sobre la tabla a escanear es accesible a través de los campos
del nodo SampleScanState (pero ten en cuenta que el descriptor de
escaneo node->ss.ss_currentScanDesc aún no está configurado).
El arreglo params, de longitud nparams, contiene los
valores de los parámetros suministrados en la cláusula TABLESAMPLE.
Estos tendrán la cantidad y los tipos especificados en la lista
parameterTypes del método de muestreo, y se ha verificado
que no sean nulos.
seed contiene una semilla para usar con cualquier número aleatorio generado
dentro del método de muestreo; es una firma hash derivada del valor de
REPEATABLE si se proporcionó uno, o el resultado
de random() en caso contrario.
Esta función puede ajustar los campos node->use_bulkread
y node->use_pagemode.
Si node->use_bulkread es true, que lo es por
defecto, el escaneo utilizará una estrategia de acceso al búfer que fomenta la
reutilización de los búferes después de su uso. Podría ser razonable establecer esto
en false si el escaneo visitará solo una pequeña fracción de las
páginas de la tabla.
Si node->use_pagemode es true, que lo es por
defecto, el escaneo realizará la verificación de visibilidad en una sola pasada para
todas las tuplas en cada página visitada. Podría ser razonable establecer esto
en false si el escaneo seleccionará solo una pequeña fracción de las
tuplas en cada página visitada. Eso resultará en que se realicen menos verificaciones de
visibilidad de tuplas, aunque cada una será más costosa porque requerirá más bloqueos.
Si el método de muestreo está
marcado como repeatable_across_scans, debe ser capaz de
seleccionar el mismo conjunto de tuplas durante un reescaneo como lo hizo originalmente, es decir,
una nueva llamada de BeginSampleScan debe conducir a la selección de las
mismas tuplas que antes (si los parámetros de TABLESAMPLE
y la semilla no cambian).
BlockNumber NextSampleBlock (SampleScanState *node, BlockNumber nblocks);
Devuelve el número de bloque de la siguiente página que se va a escanear, o
InvalidBlockNumber si no quedan páginas por escanear.
Esta función se puede omitir (establecer el puntero en NULL), en cuyo caso el código central realizará un escaneo secuencial de toda la relación. Dicho escaneo puede utilizar un escaneo sincronizado, por lo que el método de muestreo no puede asumir que las páginas de la relación se visitan en el mismo orden en cada escaneo.
OffsetNumber
NextSampleTuple (SampleScanState *node,
BlockNumber blockno,
OffsetNumber maxoffset);
Devuelve el número de desplazamiento (offset) de la siguiente tupla a muestrear en la
página especificada, o InvalidOffsetNumber si no quedan tuplas por
muestrear. maxoffset es el número de desplazamiento más grande en uso
en la página.
A NextSampleTuple no se le indica explícitamente cuáles de los números
de desplazamiento en el rango 1 .. maxoffset contienen realmente tuplas
válidas. Esto normalmente no es un problema, ya que el código central ignora
las solicitudes para muestrear tuplas faltantes o invisibles; eso no debería dar lugar a
ningún sesgo en la muestra. Sin embargo, si es necesario, la función puede usar
node->donetuples para examinar cuántas de las tuplas
que devolvió eran válidas y visibles.
NextSampleTuple no debe asumir
que blockno is the same page number returned by the most
recent NextSampleBlock call. It was returned by some
previous NextSampleBlock call, but the core code is allowed
to call NextSampleBlock in advance of actually scanning
pages, so as to support prefetching. It is OK to assume that once
sampling of a given page begins, successive NextSampleTuple
calls all refer to the same page until InvalidOffsetNumber is
returned.
void EndSampleScan (SampleScanState *node);
Finaliza el escaneo y libera los recursos. Normalmente no es importante liberar la memoria asignada con palloc, pero cualquier recurso visible externamente debe ser limpiado. Esta función se puede omitir (establecer el puntero en NULL) en el caso común de que no existan tales recursos.