User-defined functions can be written in C (or a language that can be made compatible with C, such as C++). Such functions are compiled into dynamically loadable objects (also called shared libraries) and are loaded by the server on demand. The dynamic loading feature is what distinguishes "C language" functions from "internal" functions --- the actual coding conventions are essentially the same for both. (Hence, the standard internal function library is a rich source of coding examples for user-defined C functions.)
Two different calling conventions are currently used for C functions. The newer "version 1" calling convention is indicated by writing a PG_FUNCTION_INFO_V1() macro call for the function, as illustrated below. Lack of such a macro indicates an old-style ("version 0") function. The language name specified in CREATE FUNCTION is C in either case. Old-style functions are now deprecated because of portability problems and lack of functionality, but they are still supported for compatibility reasons.
The first time a user-defined function in a particular loadable object file is called in a backend session, the dynamic loader loads that object file into memory so that the function can be called. The CREATE FUNCTION for a user-defined C function must therefore specify two pieces of information for the function: the name of the loadable object file, and the C name (link symbol) of the specific function to call within that object file. If the C name is not explicitly specified then it is assumed to be the same as the SQL function name.
The following algorithm is used to locate the shared object file based on the name given in the CREATE FUNCTION command:
If the name is an absolute path, the given file is loaded.
If the name starts with the string $libdir, that part is replaced by the PostgreSQL package library directory name, which is determined at build time.
If the name does not contain a directory part, the file is searched for in the path specified by the configuration variable dynamic_library_path.
Otherwise (the file was not found in the path, or it contains a non-absolute directory part), the dynamic loader will try to take the name as given, which will most likely fail. (It is unreliable to depend on the current working directory.)
If this sequence does not work, the platform-specific shared library file name extension (often .so) is appended to the given name and this sequence is tried again. If that fails as well, the load will fail.
Note: The user ID the PostgreSQL server runs as must be able to traverse the path to the file you intend to load. Making the file or a higher-level directory not readable and/or not executable by the "postgres" user is a common mistake.
In any case, the file name that is given in the CREATE FUNCTION command is recorded literally in the system catalogs, so if the file needs to be loaded again the same procedure is applied.
Note: PostgreSQL will not compile a C function automatically. The object file must be compiled before it is referenced in a CREATE FUNCTION command. See Section 12.5.7 for additional information.
Note: After it is used for the first time, a dynamically loaded object file is retained in memory. Future calls in the same session to the function(s) in that file will only incur the small overhead of a symbol table lookup. If you need to force a reload of an object file, for example after recompiling it, use the LOAD command or begin a fresh session.
It is recommended to locate shared libraries either relative to $libdir or through the dynamic library path. This simplifies version upgrades if the new installation is at a different location. The actual directory that $libdir stands for can be found out with the command pg_config --pkglibdir.
Note: Before PostgreSQL release 7.2, only exact absolute paths to object files could be specified in CREATE FUNCTION. This approach is now deprecated since it makes the function definition unnecessarily unportable. It's best to specify just the shared library name with no path nor extension, and let the search mechanism provide that information instead.
Table 12-1 gives the C type required for parameters in the C functions that will be loaded into PostgreSQL. The "Defined In" column gives the header file that needs to be included to get the type definition. (The actual definition may be in a different file that is included by the listed file. It is recommended that users stick to the defined interface.) Note that you should always include postgres.h first in any source file, because it declares a number of things that you will need anyway.
Table 12-1. Equivalent C Types for Built-In PostgreSQL Types
| SQL Type | C Type | Defined In |
|---|---|---|
| abstime | AbsoluteTime | utils/nabstime.h |
| boolean | bool | postgres.h (maybe compiler built-in) |
| box | BOX* | utils/geo_decls.h |
| bytea | bytea* | postgres.h |
| "char" | char | (compiler built-in) |
| character | BpChar* | postgres.h |
| cid | CommandId | postgres.h |
| date | DateADT | utils/date.h |
| smallint (int2) | int2 or int16 | postgres.h |
| int2vector | int2vector* | postgres.h |
| integer (int4) | int4 or int32 | postgres.h |
| real (float4) | float4* | postgres.h |
| double precision (float8) | float8* | postgres.h |
| interval | Interval* | utils/timestamp.h |
| lseg | LSEG* | utils/geo_decls.h |
| name | Name | postgres.h |
| oid | Oid | postgres.h |
| oidvector | oidvector* | postgres.h |
| path | PATH* | utils/geo_decls.h |
| point | POINT* | utils/geo_decls.h |
| regproc | regproc | postgres.h |
| reltime | RelativeTime | utils/nabstime.h |
| text | text* | postgres.h |
| tid | ItemPointer | storage/itemptr.h |
| time | TimeADT | utils/date.h |
| time with time zone | TimeTzADT | utils/date.h |
| timestamp | Timestamp* | utils/timestamp.h |
| tinterval | TimeInterval | utils/nabstime.h |
| varchar | VarChar* | postgres.h |
| xid | TransactionId | postgres.h |
Internally, PostgreSQL regards a base type as a "blob of memory". The user-defined functions that you define over a type in turn define the way that PostgreSQL can operate on it. That is, PostgreSQL will only store and retrieve the data from disk and use your user-defined functions to input, process, and output the data. Base types can have one of three internal formats:
pass by value, fixed-length
pass by reference, fixed-length
pass by reference, variable-length
By-value types can only be 1, 2 or 4 bytes in length (also 8 bytes, if sizeof(Datum) is 8 on your machine). You should be careful to define your types such that they will be the same size (in bytes) on all architectures. For example, the long type is dangerous because it is 4 bytes on some machines and 8 bytes on others, whereas int type is 4 bytes on most Unix machines. A reasonable implementation of the int4 type on Unix machines might be:
/* 4-byte integer, passed by value */ typedef int int4;
PostgreSQL automatically figures things out so that the integer types really have the size they advertise.
On the other hand, fixed-length types of any size may be passed by-reference. For example, here is a sample implementation of a PostgreSQL type:
/* 16-byte structure, passed by reference */
typedef struct
{
double x, y;
} Point;
Only pointers to such types can be used when passing them in and out of PostgreSQL functions. To return a value of such a type, allocate the right amount of memory with palloc(), fill in the allocated memory, and return a pointer to it. (Alternatively, you can return an input value of the same type by returning its pointer. Never modify the contents of a pass-by-reference input value, however.)
Finally, all variable-length types must also be passed by reference. All variable-length types must begin with a length field of exactly 4 bytes, and all data to be stored within that type must be located in the memory immediately following that length field. The length field is the total length of the structure (i.e., it includes the size of the length field itself). We can define the text type as follows:
typedef struct {
int4 length;
char data[1];
} text;
Obviously, the data field declared here is not long enough to hold all possible strings. Since it's impossible to declare a variable-size structure in C, we rely on the knowledge that the C compiler won't range-check array subscripts. We just allocate the necessary amount of space and then access the array as if it were declared the right length. (If this isn't a familiar trick to you, you may wish to spend some time with an introductory C programming textbook before delving deeper into PostgreSQL server programming.) When manipulating variable-length types, we must be careful to allocate the correct amount of memory and set the length field correctly. For example, if we wanted to store 40 bytes in a text structure, we might use a code fragment like this:
#include "postgres.h" ... char buffer[40]; /* our source data */ ... text *destination = (text *) palloc(VARHDRSZ + 40); destination->length = VARHDRSZ + 40; memcpy(destination->data, buffer, 40); ...
VARHDRSZ is the same as sizeof(int4), but it's considered good style to use the macro VARHDRSZ to refer to the size of the overhead for a variable-length type.
Now that we've gone over all of the possible structures for base types, we can show some examples of real functions.
We present the "old style" calling convention first --- although this approach is now deprecated, it's easier to get a handle on initially. In the version-0 method, the arguments and result of the C function are just declared in normal C style, but being careful to use the C representation of each SQL data type as shown above.
Here are some examples:
#include "postgres.h"
#include <string.h>
/* By Value */
int
add_one(int arg)
{
return arg + 1;
}
/* By Reference, Fixed Length */
float8 *
add_one_float8(float8 *arg)
{
float8 *result = (float8 *) palloc(sizeof(float8));
*result = *arg + 1.0;
return result;
}
Point *
makepoint(Point *pointx, Point *pointy)
{
Point *new_point = (Point *) palloc(sizeof(Point));
new_point->x = pointx->x;
new_point->y = pointy->y;
return new_point;
}
/* By Reference, Variable Length */
text *
copytext(text *t)
{
/*
* VARSIZE is the total size of the struct in bytes.
*/
text *new_t = (text *) palloc(VARSIZE(t));
VARATT_SIZEP(new_t) = VARSIZE(t);
/*
* VARDATA is a pointer to the data region of the struct.
*/
memcpy((void *) VARDATA(new_t), /* destination */
(void *) VARDATA(t), /* source */
VARSIZE(t)-VARHDRSZ); /* how many bytes */
return new_t;
}
text *
concat_text(text *arg1, text *arg2)
{
int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
text *new_text = (text *) palloc(new_text_size);
VARATT_SIZEP(new_text) = new_text_size;
memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ);
memcpy(VARDATA(new_text) + (VARSIZE(arg1)-VARHDRSZ),
VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ);
return new_text;
}
Supposing that the above code has been prepared in file funcs.c and compiled into a shared object, we could define the functions to PostgreSQL with commands like this:
CREATE FUNCTION add_one(int4) RETURNS int4
AS 'PGROOT/tutorial/funcs' LANGUAGE C
WITH (isStrict);
-- note overloading of SQL function name add_one()
CREATE FUNCTION add_one(float8) RETURNS float8
AS 'PGROOT/tutorial/funcs',
'add_one_float8'
LANGUAGE C WITH (isStrict);
CREATE FUNCTION makepoint(point, point) RETURNS point
AS 'PGROOT/tutorial/funcs' LANGUAGE C
WITH (isStrict);
CREATE FUNCTION copytext(text) RETURNS text
AS 'PGROOT/tutorial/funcs' LANGUAGE C
WITH (isStrict);
CREATE FUNCTION concat_text(text, text) RETURNS text
AS 'PGROOT/tutorial/funcs' LANGUAGE C
WITH (isStrict);
Here PGROOT stands for the full path to the PostgreSQL source tree. (Better style would be to use just 'funcs' in the AS clause, after having added PGROOT/tutorial to the search path. In any case, we may omit the system-specific extension for a shared library, commonly .so or .sl.)
Notice that we have specified the functions as "strict", meaning that the system should automatically assume a NULL result if any input value is NULL. By doing this, we avoid having to check for NULL inputs in the function code. Without this, we'd have to check for NULLs explicitly, for example by checking for a null pointer for each pass-by-reference argument. (For pass-by-value arguments, we don't even have a way to check!)
Although this calling convention is simple to use, it is not very portable; on some architectures there are problems with passing smaller-than-int data types this way. Also, there is no simple way to return a NULL result, nor to cope with NULL arguments in any way other than making the function strict. The version-1 convention, presented next, overcomes these objections.
The version-1 calling convention relies on macros to suppress most of the complexity of passing arguments and results. The C declaration of a version-1 function is always
Datum funcname(PG_FUNCTION_ARGS)
In addition, the macro call
PG_FUNCTION_INFO_V1(funcname);
must appear in the same source file (conventionally it's written just before the function itself). This macro call is not needed for internal-language functions, since PostgreSQL currently assumes all internal functions are version-1. However, it is required for dynamically-loaded functions.
In a version-1 function, each actual argument is fetched using a PG_GETARG_xxx() macro that corresponds to the argument's datatype, and the result is returned using a PG_RETURN_xxx() macro for the return type.
Here we show the same functions as above, coded in version-1 style:
#include "postgres.h"
#include <string.h>
#include "fmgr.h"
/* By Value */
PG_FUNCTION_INFO_V1(add_one);
Datum
add_one(PG_FUNCTION_ARGS)
{
int32 arg = PG_GETARG_INT32(0);
PG_RETURN_INT32(arg + 1);
}
/* By Reference, Fixed Length */
PG_FUNCTION_INFO_V1(add_one_float8);
Datum
add_one_float8(PG_FUNCTION_ARGS)
{
/* The macros for FLOAT8 hide its pass-by-reference nature */
float8 arg = PG_GETARG_FLOAT8(0);
PG_RETURN_FLOAT8(arg + 1.0);
}
PG_FUNCTION_INFO_V1(makepoint);
Datum
makepoint(PG_FUNCTION_ARGS)
{
/* Here, the pass-by-reference nature of Point is not hidden */
Point *pointx = PG_GETARG_POINT_P(0);
Point *pointy = PG_GETARG_POINT_P(1);
Point *new_point = (Point *) palloc(sizeof(Point));
new_point->x = pointx->x;
new_point->y = pointy->y;
PG_RETURN_POINT_P(new_point);
}
/* By Reference, Variable Length */
PG_FUNCTION_INFO_V1(copytext);
Datum
copytext(PG_FUNCTION_ARGS)
{
text *t = PG_GETARG_TEXT_P(0);
/*
* VARSIZE is the total size of the struct in bytes.
*/
text *new_t = (text *) palloc(VARSIZE(t));
VARATT_SIZEP(new_t) = VARSIZE(t);
/*
* VARDATA is a pointer to the data region of the struct.
*/
memcpy((void *) VARDATA(new_t), /* destination */
(void *) VARDATA(t), /* source */
VARSIZE(t)-VARHDRSZ); /* how many bytes */
PG_RETURN_TEXT_P(new_t);
}
PG_FUNCTION_INFO_V1(concat_text);
Datum
concat_text(PG_FUNCTION_ARGS)
{
text *arg1 = PG_GETARG_TEXT_P(0);
text *arg2 = PG_GETARG_TEXT_P(1);
int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
text *new_text = (text *) palloc(new_text_size);
VARATT_SIZEP(new_text) = new_text_size;
memcpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ);
memcpy(VARDATA(new_text) + (VARSIZE(arg1)-VARHDRSZ),
VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ);
PG_RETURN_TEXT_P(new_text);
}
The CREATE FUNCTION commands are the same as for the version-0 equivalents.
At first glance, the version-1 coding conventions may appear to be just pointless obscurantism. However, they do offer a number of improvements, because the macros can hide unnecessary detail. An example is that in coding add_one_float8, we no longer need to be aware that float8 is a pass-by-reference type. Another example is that the GETARG macros for variable-length types hide the need to deal with fetching "toasted" (compressed or out-of-line) values. The old-style copytext and concat_text functions shown above are actually wrong in the presence of toasted values, because they don't call pg_detoast_datum() on their inputs. (The handler for old-style dynamically-loaded functions currently takes care of this detail, but it does so less efficiently than is possible for a version-1 function.)
One big improvement in version-1 functions is better handling of NULL inputs and results. The macro PG_ARGISNULL(n) allows a function to test whether each input is NULL (of course, doing this is only necessary in functions not declared "strict"). As with the PG_GETARG_xxx() macros, the input arguments are counted beginning at zero. Note that one should refrain from executing PG_GETARG_xxx() until one has verified that the argument isn't NULL. To return a NULL result, execute PG_RETURN_NULL(); this works in both strict and nonstrict functions.
The version-1 function call conventions make it possible to return "set" results and implement trigger functions and procedural-language call handlers. Version-1 code is also more portable than version-0, because it does not break ANSI C restrictions on function call protocol. For more details see src/backend/utils/fmgr/README in the source distribution.
Composite types do not have a fixed layout like C structures. Instances of a composite type may contain null fields. In addition, composite types that are part of an inheritance hierarchy may have different fields than other members of the same inheritance hierarchy. Therefore, PostgreSQL provides a procedural interface for accessing fields of composite types from C. As PostgreSQL processes a set of rows, each row will be passed into your function as an opaque structure of type TUPLE. Suppose we want to write a function to answer the query
SELECT name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpaid(emp, 1500) AS overpaid FROM emp WHERE name = 'T name, c_overpa