Patches for the SGML documentation relating
to the tutorial code changes. NOTE: I couldn't get ngsmls to find the document type so that the changes could be checked. However, the changes were very minor: Best, Clark
This commit is contained in:
parent
344190b7ef
commit
f45ec44c6b
@ -7,19 +7,20 @@
|
|||||||
Consequently, while it is possible to define a new
|
Consequently, while it is possible to define a new
|
||||||
function without defining a new type, the reverse is
|
function without defining a new type, the reverse is
|
||||||
not true. We therefore describe how to add new functions
|
not true. We therefore describe how to add new functions
|
||||||
to <ProductName>Postgres</ProductName> before describing how to add new
|
to <ProductName>Postgres</ProductName> before describing
|
||||||
types.
|
how to add new types.
|
||||||
<ProductName>Postgres</ProductName> <Acronym>SQL</Acronym> provides two types of functions: query
|
<ProductName>Postgres</ProductName> <Acronym>SQL</Acronym>
|
||||||
language functions (functions written in <Acronym>SQL</Acronym> and
|
provides two types of functions: query language functions
|
||||||
programming language functions (functions written in a
|
(functions written in <Acronym>SQL</Acronym> and programming
|
||||||
compiled programming language such as <Acronym>C</Acronym>.) Either kind
|
language functions (functions written in a compiled
|
||||||
|
programming language such as <Acronym>C</Acronym>.) Either kind
|
||||||
of function can take a base type, a composite type or
|
of function can take a base type, a composite type or
|
||||||
some combination as arguments (parameters). In addition,
|
some combination as arguments (parameters). In addition,
|
||||||
both kinds of functions can return a base type or
|
both kinds of functions can return a base type or
|
||||||
a composite type. It's easier to define <Acronym>SQL</Acronym> functions,
|
a composite type. It's easier to define <Acronym>SQL</Acronym>
|
||||||
so we'll start with those.
|
functions, so we'll start with those. Examples in this section
|
||||||
Examples in this section can also be found in <FileName>funcs.sql</FileName>
|
can also be found in <FileName>funcs.sql</FileName>
|
||||||
and <FileName>C-code/funcs.c</FileName>.
|
and <FileName>funcs.c</FileName>.
|
||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
<Sect1>
|
<Sect1>
|
||||||
@ -54,8 +55,8 @@
|
|||||||
instead of one.
|
instead of one.
|
||||||
</Para>
|
</Para>
|
||||||
<Para>
|
<Para>
|
||||||
It's almost as easy to define <Acronym>SQL</Acronym> functions that take
|
It's almost as easy to define <Acronym>SQL</Acronym> functions
|
||||||
base types as arguments. In the example below, notice
|
that take base types as arguments. In the example below, notice
|
||||||
how we refer to the arguments within the function as $1
|
how we refer to the arguments within the function as $1
|
||||||
and $2.
|
and $2.
|
||||||
|
|
||||||
@ -91,7 +92,8 @@
|
|||||||
|
|
||||||
SELECT name, double_salary(EMP) AS dream
|
SELECT name, double_salary(EMP) AS dream
|
||||||
FROM EMP
|
FROM EMP
|
||||||
WHERE EMP.dept = 'toy';
|
WHERE EMP.cubicle ~= '(2,1)'::point;
|
||||||
|
|
||||||
|
|
||||||
+-----+-------+
|
+-----+-------+
|
||||||
|name | dream |
|
|name | dream |
|
||||||
@ -137,7 +139,7 @@
|
|||||||
AS 'SELECT \'None\'::text AS name,
|
AS 'SELECT \'None\'::text AS name,
|
||||||
1000 AS salary,
|
1000 AS salary,
|
||||||
25 AS age,
|
25 AS age,
|
||||||
\'none\'::text AS dept;'
|
\'(2,2)\'::point AS cubicle'
|
||||||
LANGUAGE 'sql';
|
LANGUAGE 'sql';
|
||||||
</ProgramListing>
|
</ProgramListing>
|
||||||
|
|
||||||
@ -153,15 +155,15 @@
|
|||||||
<ItemizedList>
|
<ItemizedList>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Para>
|
<Para>
|
||||||
The target list order must be exactly the same as
|
The target list order must be exactly the same as
|
||||||
that in which the attributes appear in the CREATE
|
that in which the attributes appear in the CREATE
|
||||||
TABLE statement (or when you execute a .* query).
|
TABLE statement (or when you execute a .* query).
|
||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Para>
|
<Para>
|
||||||
You must typecast the expressions
|
You must typecast the expressions (using ::) very carefully
|
||||||
(using ::) very carefully or you will see the following error:
|
or you will see the following error:
|
||||||
|
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
WARN::function declared to return type EMP does not retrieve (EMP.*)
|
WARN::function declared to return type EMP does not retrieve (EMP.*)
|
||||||
@ -202,11 +204,12 @@ The reason why, in general, we must use the function
|
|||||||
</ItemizedList>
|
</ItemizedList>
|
||||||
</para>
|
</para>
|
||||||
<Para>
|
<Para>
|
||||||
Any collection of commands in the <Acronym>SQL</Acronym> query language
|
Any collection of commands in the <Acronym>SQL</Acronym> query
|
||||||
can be packaged together and defined as a function.
|
language can be packaged together and defined as a function.
|
||||||
The commands can include updates (i.e., <Acronym>insert</Acronym>, <Acronym>update</Acronym>
|
The commands can include updates (i.e., <Acronym>insert</Acronym>,
|
||||||
and <Acronym>delete</Acronym>) as well as <Acronym>select</Acronym> queries. However, the
|
<Acronym>update</Acronym> and <Acronym>delete</Acronym>) as well
|
||||||
final command must be a <Acronym>select</Acronym> that returns whatever is
|
as <Acronym>select</Acronym> queries. However, the final command
|
||||||
|
must be a <Acronym>select</Acronym> that returns whatever is
|
||||||
specified as the function's returntype.
|
specified as the function's returntype.
|
||||||
|
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
@ -222,6 +225,7 @@ The reason why, in general, we must use the function
|
|||||||
+--+
|
+--+
|
||||||
|1 |
|
|1 |
|
||||||
+--+
|
+--+
|
||||||
|
|
||||||
</ProgramListing>
|
</ProgramListing>
|
||||||
</Para>
|
</Para>
|
||||||
</sect2>
|
</sect2>
|
||||||
@ -234,12 +238,13 @@ The reason why, in general, we must use the function
|
|||||||
<Title>Programming Language Functions on Base Types</Title>
|
<Title>Programming Language Functions on Base Types</Title>
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
Internally, <ProductName>Postgres</ProductName> regards a base type as a "blob of
|
Internally, <ProductName>Postgres</ProductName> regards a
|
||||||
memory." The user-defined functions that you define
|
base type as a "blob of memory." The user-defined
|
||||||
over a type in turn define the way that <ProductName>Postgres</ProductName> can
|
functions that you define over a type in turn define the
|
||||||
operate on it. That is, <ProductName>Postgres</ProductName> will only store and
|
way that <ProductName>Postgres</ProductName> can operate
|
||||||
retrieve the data from disk and use your user-defined
|
on it. That is, <ProductName>Postgres</ProductName> will
|
||||||
functions to input, process, and output the data.
|
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:
|
Base types can have one of three internal formats:
|
||||||
<ItemizedList>
|
<ItemizedList>
|
||||||
<ListItem><Para>pass by value, fixed-length</Para>
|
<ListItem><Para>pass by value, fixed-length</Para>
|
||||||
@ -254,14 +259,16 @@ The reason why, in general, we must use the function
|
|||||||
<Para>
|
<Para>
|
||||||
By-value types can only be 1, 2 or 4 bytes in length
|
By-value types can only be 1, 2 or 4 bytes in length
|
||||||
(even if your computer supports by-value types of other
|
(even if your computer supports by-value types of other
|
||||||
sizes). <ProductName>Postgres</ProductName> itself only passes integer types by
|
sizes). <ProductName>Postgres</ProductName> itself
|
||||||
value. You should be careful to define your types such
|
only passes integer types by value. You should be careful
|
||||||
that they will be the same size (in bytes) on all
|
to define your types such that they will be the same
|
||||||
architectures. For example, the <Acronym>long</Acronym> type is dangerous
|
size (in bytes) on all architectures. For example, the
|
||||||
because it is 4 bytes on some machines and 8 bytes on
|
<Acronym>long</Acronym> type is dangerous because it
|
||||||
others, whereas <Acronym>int</Acronym> type is 4 bytes on most <Acronym>UNIX</Acronym>
|
is 4 bytes on some machines and 8 bytes on others, whereas
|
||||||
machines (though not on most personal computers). A
|
<Acronym>int</Acronym> type is 4 bytes on most
|
||||||
reasonable implementation of the <Acronym>int4</Acronym> type on <Acronym>UNIX</Acronym>
|
<Acronym>UNIX</Acronym> machines (though not on most
|
||||||
|
personal computers). A reasonable implementation of
|
||||||
|
the <Acronym>int4</Acronym> type on <Acronym>UNIX</Acronym>
|
||||||
machines might be:
|
machines might be:
|
||||||
|
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
@ -277,9 +284,10 @@ The reason why, in general, we must use the function
|
|||||||
|
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
/* 16-byte structure, passed by reference */
|
/* 16-byte structure, passed by reference */
|
||||||
typedef struct {
|
typedef struct
|
||||||
char data[16];
|
{
|
||||||
} char16;
|
double x, y;
|
||||||
|
} Point;
|
||||||
</ProgramListing>
|
</ProgramListing>
|
||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
@ -308,10 +316,10 @@ The reason why, in general, we must use the function
|
|||||||
<Para>
|
<Para>
|
||||||
Obviously, the data field is not long enough to hold
|
Obviously, the data field is not long enough to hold
|
||||||
all possible strings -- it's impossible to declare such
|
all possible strings -- it's impossible to declare such
|
||||||
a structure in <Acronym>C</Acronym>. When manipulating variable-length
|
a structure in <Acronym>C</Acronym>. When manipulating
|
||||||
types, we must be careful to allocate the correct
|
variable-length types, we must be careful to allocate
|
||||||
amount of memory and initialize the length field. For
|
the correct amount of memory and initialize the length field.
|
||||||
example, if we wanted to store 40 bytes in a text
|
For example, if we wanted to store 40 bytes in a text
|
||||||
structure, we might use a code fragment like this:
|
structure, we might use a code fragment like this:
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -332,23 +340,30 @@ The reason why, in general, we must use the function
|
|||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
/* By Value */
|
||||||
|
|
||||||
int
|
int
|
||||||
add_one(int arg)
|
add_one(int arg)
|
||||||
{
|
{
|
||||||
return(arg + 1);
|
return(arg + 1);
|
||||||
}
|
}
|
||||||
text *
|
|
||||||
concat_text(text *arg1, text *arg2)
|
|
||||||
{
|
|
||||||
int32 new_text_size = VARSIZE(arg1) + VARSIZE(arg2) - VARHDRSZ;
|
|
||||||
text *new_text = (text *) palloc(new_text_size);
|
|
||||||
|
|
||||||
memset((void *) new_text, 0, new_text_size);
|
/* By Reference, Fixed Length */
|
||||||
VARSIZE(new_text) = new_text_size;
|
|
||||||
strncpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ);
|
Point *
|
||||||
strncat(VARDATA(new_text), VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ);
|
makepoint(Point *pointx, Point *pointy )
|
||||||
return (new_text);
|
{
|
||||||
|
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 *
|
text *
|
||||||
copytext(text *t)
|
copytext(text *t)
|
||||||
{
|
{
|
||||||
@ -366,6 +381,19 @@ The reason why, in general, we must use the function
|
|||||||
VARSIZE(t)-VARHDRSZ); /* how many bytes */
|
VARSIZE(t)-VARHDRSZ); /* how many bytes */
|
||||||
return(new_t);
|
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);
|
||||||
|
|
||||||
|
memset((void *) new_text, 0, new_text_size);
|
||||||
|
VARSIZE(new_text) = new_text_size;
|
||||||
|
strncpy(VARDATA(new_text), VARDATA(arg1), VARSIZE(arg1)-VARHDRSZ);
|
||||||
|
strncat(VARDATA(new_text), VARDATA(arg2), VARSIZE(arg2)-VARHDRSZ);
|
||||||
|
return (new_text);
|
||||||
|
}
|
||||||
</ProgramListing>
|
</ProgramListing>
|
||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
@ -374,13 +402,16 @@ The reason why, in general, we must use the function
|
|||||||
|
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
CREATE FUNCTION add_one(int4) RETURNS int4
|
CREATE FUNCTION add_one(int4) RETURNS int4
|
||||||
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
|
AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c';
|
||||||
|
|
||||||
|
CREATE FUNCTION makepoint(point, point) RETURNS point
|
||||||
|
AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c';
|
||||||
|
|
||||||
CREATE FUNCTION concat_text(text, text) RETURNS text
|
CREATE FUNCTION concat_text(text, text) RETURNS text
|
||||||
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
|
AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c';
|
||||||
|
|
||||||
CREATE FUNCTION copytext(text) RETURNS text
|
CREATE FUNCTION copytext(text) RETURNS text
|
||||||
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
|
AS 'PGROOT/tutorial/funcs.so' LANGUAGE 'c';
|
||||||
</ProgramListing>
|
</ProgramListing>
|
||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
@ -399,11 +430,11 @@ The reason why, in general, we must use the function
|
|||||||
null fields. In addition, composite types that are
|
null fields. In addition, composite types that are
|
||||||
part of an inheritance hierarchy may have different
|
part of an inheritance hierarchy may have different
|
||||||
fields than other members of the same inheritance hierarchy.
|
fields than other members of the same inheritance hierarchy.
|
||||||
Therefore, <ProductName>Postgres</ProductName> provides a procedural
|
Therefore, <ProductName>Postgres</ProductName> provides
|
||||||
interface for accessing fields of composite types from
|
a procedural interface for accessing fields of composite types
|
||||||
C.
|
from C. As <ProductName>Postgres</ProductName> processes
|
||||||
As <ProductName>Postgres</ProductName> processes a set of instances, each instance
|
a set of instances, each instance will be passed into your
|
||||||
will be passed into your function as an opaque structure of type <Acronym>TUPLE</Acronym>.
|
function as an opaque structure of type <Acronym>TUPLE</Acronym>.
|
||||||
Suppose we want to write a function to answer the query
|
Suppose we want to write a function to answer the query
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
* SELECT name, c_overpaid(EMP, 1500) AS overpaid
|
* SELECT name, c_overpaid(EMP, 1500) AS overpaid
|
||||||
@ -414,9 +445,10 @@ The reason why, in general, we must use the function
|
|||||||
|
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
#include "libpq-fe.h" /* for TUPLE */
|
#include "executor/executor.h" /* for GetAttributeByName() */
|
||||||
|
|
||||||
bool
|
bool
|
||||||
c_overpaid(TUPLE t,/* the current instance of EMP */
|
c_overpaid(TupleTableSlot *t, /* the current instance of EMP */
|
||||||
int4 limit)
|
int4 limit)
|
||||||
{
|
{
|
||||||
bool isnull = false;
|
bool isnull = false;
|
||||||
@ -430,16 +462,17 @@ The reason why, in general, we must use the function
|
|||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
<Acronym>GetAttributeByName</Acronym> is the <ProductName>Postgres</ProductName> system function that
|
<Acronym>GetAttributeByName</Acronym> is the
|
||||||
|
<ProductName>Postgres</ProductName> system function that
|
||||||
returns attributes out of the current instance. It has
|
returns attributes out of the current instance. It has
|
||||||
three arguments: the argument of type TUPLE passed into
|
three arguments: the argument of type TUPLE passed into
|
||||||
the function, the name of the desired attribute, and a
|
the function, the name of the desired attribute, and a
|
||||||
return parameter that describes whether the attribute
|
return parameter that describes whether the attribute
|
||||||
is null. <Acronym>GetAttributeByName</Acronym> will align data properly
|
is null. <Acronym>GetAttributeByName</Acronym> will
|
||||||
so you can cast its return value to the desired type.
|
align data properly so you can cast its return value to
|
||||||
For example, if you have an attribute name which is of
|
the desired type. For example, if you have an attribute
|
||||||
the type name, the <Acronym>GetAttributeByName</Acronym> call would look
|
name which is of the type name, the <Acronym>GetAttributeByName</Acronym>
|
||||||
like:
|
call would look like:
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
char *str;
|
char *str;
|
||||||
...
|
...
|
||||||
@ -448,8 +481,8 @@ The reason why, in general, we must use the function
|
|||||||
</Para>
|
</Para>
|
||||||
|
|
||||||
<Para>
|
<Para>
|
||||||
The following query lets <ProductName>Postgres</ProductName> know about the
|
The following query lets <ProductName>Postgres</ProductName>
|
||||||
c_overpaid function:
|
know about the c_overpaid function:
|
||||||
<ProgramListing>
|
<ProgramListing>
|
||||||
* CREATE FUNCTION c_overpaid(EMP, int4) RETURNS bool
|
* CREATE FUNCTION c_overpaid(EMP, int4) RETURNS bool
|
||||||
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
|
AS 'PGROOT/tutorial/obj/funcs.so' LANGUAGE 'c';
|
||||||
@ -470,24 +503,28 @@ The reason why, in general, we must use the function
|
|||||||
We now turn to the more difficult task of writing
|
We now turn to the more difficult task of writing
|
||||||
programming language functions. Be warned: this section
|
programming language functions. Be warned: this section
|
||||||
of the manual will not make you a programmer. You must
|
of the manual will not make you a programmer. You must
|
||||||
have a good understanding of <Acronym>C</Acronym> (including the use of
|
have a good understanding of <Acronym>C</Acronym>
|
||||||
pointers and the malloc memory manager) before trying
|
(including the use of pointers and the malloc memory manager)
|
||||||
to write <Acronym>C</Acronym> functions for use with <ProductName>Postgres</ProductName>.
|
before trying to write <Acronym>C</Acronym> functions for
|
||||||
While it may be possible to load functions written in
|
use with <ProductName>Postgres</ProductName>. While it may
|
||||||
languages other than <Acronym>C</Acronym> into <ProductName>Postgres</ProductName>, this is often
|
be possible to load functions written in languages other
|
||||||
difficult (when it is possible at all) because other
|
than <Acronym>C</Acronym> into <ProductName>Postgres</ProductName>,
|
||||||
languages, such as <Acronym>FORTRAN</Acronym> and <Acronym>Pascal</Acronym> often do not follow
|
this is often difficult (when it is possible at all)
|
||||||
the same "calling convention" as <Acronym>C</Acronym>. That is, other
|
because other languages, such as <Acronym>FORTRAN</Acronym>
|
||||||
|
and <Acronym>Pascal</Acronym> often do not follow the same
|
||||||
|
"calling convention" as <Acronym>C</Acronym>. That is, other
|
||||||
languages do not pass argument and return values
|
languages do not pass argument and return values
|
||||||
between functions in the same way. For this reason, we
|
between functions in the same way. For this reason, we
|
||||||
will assume that your programming language functions
|
will assume that your programming language functions
|
||||||
are written in <Acronym>C</Acronym>.
|
are written in <Acronym>C</Acronym>.
|
||||||
The basic rules for building <Acronym>C</Acronym> functions are as follows:
|
The basic rules for building <Acronym>C</Acronym> functions
|
||||||
|
are as follows:
|
||||||
|
|
||||||
<ItemizedList>
|
<ItemizedList>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Para>
|
<Para>
|
||||||
Most of the header (include) files for <ProductName>Postgres</ProductName>
|
Most of the header (include) files for
|
||||||
|
<ProductName>Postgres</ProductName>
|
||||||
should already be installed in
|
should already be installed in
|
||||||
<FileName>PGROOT/include</FileName> (see Figure 2).
|
<FileName>PGROOT/include</FileName> (see Figure 2).
|
||||||
You should always include
|
You should always include
|
||||||
@ -511,9 +548,11 @@ Most of the header (include) files for <ProductName>Postgres</ProductName>
|
|||||||
</para>
|
</para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Para> When allocating memory, use the <ProductName>Postgres</ProductName>
|
<Para> When allocating memory, use the
|
||||||
|
<ProductName>Postgres</ProductName>
|
||||||
routines palloc and pfree instead of the
|
routines palloc and pfree instead of the
|
||||||
corresponding <Acronym>C</Acronym> library routines malloc and free.
|
corresponding <Acronym>C</Acronym> library routines
|
||||||
|
malloc and free.
|
||||||
The memory allocated by palloc will be freed
|
The memory allocated by palloc will be freed
|
||||||
automatically at the end of each transaction,
|
automatically at the end of each transaction,
|
||||||
preventing memory leaks.
|
preventing memory leaks.
|
||||||
@ -531,15 +570,16 @@ Most of the header (include) files for <ProductName>Postgres</ProductName>
|
|||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Para> Most of the internal <ProductName>Postgres</ProductName> types are declared
|
<Para> Most of the internal <ProductName>Postgres</ProductName>
|
||||||
in postgres.h, so it's a good idea to always
|
types are declared in postgres.h, so it's a good
|
||||||
include that file as well. Including postgres.h
|
idea to always include that file as well. Including
|
||||||
will also include elog.h and palloc.h for you.
|
postgres.h will also include elog.h and palloc.h for you.
|
||||||
</Para>
|
</Para>
|
||||||
</ListItem>
|
</ListItem>
|
||||||
<ListItem>
|
<ListItem>
|
||||||
<Para> Compiling and loading your object code so that
|
<Para> Compiling and loading your object code so that
|
||||||
it can be dynamically loaded into <ProductName>Postgres</ProductName>
|
it can be dynamically loaded into
|
||||||
|
<ProductName>Postgres</ProductName>
|
||||||
always requires special flags. See Appendix A
|
always requires special flags. See Appendix A
|
||||||
for a detailed explanation of how to do it for
|
for a detailed explanation of how to do it for
|
||||||
your particular operating system.
|
your particular operating system.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user