Skip to content

Commit 6206a88

Browse files
committed
Add SQL99 CONVERT() function.
1 parent 34f03b1 commit 6206a88

File tree

15 files changed

+1237
-211
lines changed

15 files changed

+1237
-211
lines changed

doc/src/sgml/func.sgml

Lines changed: 413 additions & 1 deletion
Large diffs are not rendered by default.

src/backend/catalog/namespace.c

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
* Portions Copyright (c) 1994, Regents of the University of California
1414
*
1515
* IDENTIFICATION
16-
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.27 2002/07/29 23:46:35 tgl Exp $
16+
* $Header: /cvsroot/pgsql/src/backend/catalog/namespace.c,v 1.28 2002/08/06 05:40:44 ishii Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -1238,6 +1238,43 @@ PopSpecialNamespace(Oid namespaceId)
12381238
namespaceSearchPathValid = false;
12391239
}
12401240

1241+
/*
1242+
* FindConversionByName - find a conversion by possibly qualified name
1243+
*/
1244+
Oid FindConversionByName(List *name)
1245+
{
1246+
char *conversion_name;
1247+
Oid namespaceId;
1248+
Oid conoid;
1249+
List *lptr;
1250+
1251+
/* Convert list of names to a name and namespace */
1252+
namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name);
1253+
1254+
if (length(name) > 1)
1255+
{
1256+
/* Check we have usage rights in target namespace */
1257+
if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
1258+
return InvalidOid;
1259+
1260+
return FindConversion(conversion_name, namespaceId);
1261+
}
1262+
1263+
recomputeNamespacePath();
1264+
1265+
foreach(lptr, namespaceSearchPath)
1266+
{
1267+
Oid namespaceId = (Oid) lfirsti(lptr);
1268+
1269+
conoid = FindConversion(conversion_name, namespaceId);
1270+
if (OidIsValid(conoid))
1271+
return conoid;
1272+
}
1273+
1274+
/* Not found in path */
1275+
return InvalidOid;
1276+
}
1277+
12411278
/*
12421279
* FindDefaultConversionProc - find default encoding cnnversion proc
12431280
*/

src/backend/catalog/pg_conversion.c

Lines changed: 74 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.4 2002/08/05 03:29:16 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v 1.5 2002/08/06 05:40:45 ishii Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -221,7 +221,7 @@ RemoveConversionById(Oid conversionOid)
221221
if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
222222
simple_heap_delete(rel, &tuple->t_self);
223223
else
224-
elog(ERROR, "Conversion %u does not exist", conversionOid);
224+
elog(ERROR, "conversion %u does not exist", conversionOid);
225225
heap_endscan(scan);
226226
heap_close(rel, RowExclusiveLock);
227227
}
@@ -233,47 +233,6 @@ RemoveConversionById(Oid conversionOid)
233233
* If found, returns the procedure's oid, otherwise InvalidOid.
234234
* ---------------
235235
*/
236-
#ifdef NOT_USED
237-
Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
238-
{
239-
Relation rel;
240-
HeapScanDesc scan;
241-
ScanKeyData scanKeyData;
242-
HeapTuple tuple;
243-
Form_pg_conversion body;
244-
Oid proc = InvalidOid;
245-
246-
/* Check we have usage rights in target namespace */
247-
if (pg_namespace_aclcheck(name_space, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
248-
return InvalidOid;
249-
250-
ScanKeyEntryInitialize(&scanKeyData,
251-
0,
252-
Anum_pg_conversion_connamespace,
253-
F_OIDEQ,
254-
ObjectIdGetDatum(name_space));
255-
256-
rel = heap_openr(ConversionRelationName, AccessShareLock);
257-
scan = heap_beginscan(rel, SnapshotNow,
258-
1, &scanKeyData);
259-
260-
while (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection)))
261-
{
262-
body = (Form_pg_conversion)GETSTRUCT(tuple);
263-
if (body->conforencoding == for_encoding &&
264-
body->contoencoding == to_encoding &&
265-
body->condefault == TRUE)
266-
{
267-
proc = body->conproc;
268-
break;
269-
}
270-
}
271-
heap_endscan(scan);
272-
heap_close(rel, AccessShareLock);
273-
return proc;
274-
}
275-
#endif
276-
277236
Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
278237
{
279238
CatCList *catlist;
@@ -309,34 +268,27 @@ Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding)
309268
/* ----------------
310269
* FindConversionByName
311270
*
312-
* Find conversion proc by possibly qualified conversion name.
271+
* Find conversion by namespace and conversion name.
272+
* Returns conversion oid.
313273
* ---------------
314274
*/
315-
Oid FindConversionByName(List *name)
275+
Oid FindConversion(const char *conname, Oid connamespace)
316276
{
317277
HeapTuple tuple;
318-
char *conversion_name;
319-
Oid namespaceId;
320278
Oid procoid;
279+
Oid conoid;
321280
AclResult aclresult;
322281

323-
/* Convert list of names to a name and namespace */
324-
namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name);
325-
326-
/* Check we have usage rights in target namespace */
327-
if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK)
328-
return InvalidOid;
329-
330-
/* search pg_conversion by namespaceId and conversion name */
282+
/* search pg_conversion by connamespace and conversion name */
331283
tuple = SearchSysCache(CONNAMESP,
332-
PointerGetDatum(conversion_name),
333-
ObjectIdGetDatum(namespaceId),
284+
PointerGetDatum(conname),
285+
ObjectIdGetDatum(connamespace),
334286
0,0);
335287

336288
if (!HeapTupleIsValid(tuple))
337289
return InvalidOid;
338-
339290
procoid = ((Form_pg_conversion)GETSTRUCT(tuple))->conproc;
291+
conoid = HeapTupleGetOid(tuple);
340292

341293
ReleaseSysCache(tuple);
342294

@@ -345,6 +297,69 @@ Oid FindConversionByName(List *name)
345297
if (aclresult != ACLCHECK_OK)
346298
return InvalidOid;
347299

348-
return procoid;
300+
return conoid;
349301
}
350302

303+
/*
304+
* Execute SQL99's CONVERT function.
305+
*
306+
* CONVERT <left paren> <character value expression>
307+
* USING <form-of-use conversion name> <right paren>
308+
*
309+
* TEXT convert3(TEXT string, OID conversion_oid);
310+
*/
311+
Datum
312+
pg_convert3(PG_FUNCTION_ARGS)
313+
{
314+
text *string = PG_GETARG_TEXT_P(0);
315+
Oid convoid = PG_GETARG_OID(1);
316+
HeapTuple tuple;
317+
Form_pg_conversion body;
318+
text *retval;
319+
unsigned char *str;
320+
unsigned char *result;
321+
int len;
322+
323+
if (!OidIsValid(convoid))
324+
elog(ERROR, "Conversion does not exist");
325+
326+
/* make sure that source string is null terminated */
327+
len = VARSIZE(string) - VARHDRSZ;
328+
str = palloc(len + 1);
329+
memcpy(str, VARDATA(string), len);
330+
*(str + len) = '\0';
331+
332+
tuple = SearchSysCache(CONOID,
333+
ObjectIdGetDatum(convoid),
334+
0,0,0);
335+
if (!HeapTupleIsValid(tuple))
336+
elog(ERROR, "Conversion %u search from syscache failed", convoid);
337+
338+
result = palloc(len * 4 + 1);
339+
340+
body = (Form_pg_conversion)GETSTRUCT(tuple);
341+
OidFunctionCall5(body->conproc,
342+
Int32GetDatum(body->conforencoding),
343+
Int32GetDatum(body->contoencoding),
344+
CStringGetDatum(str),
345+
CStringGetDatum(result),
346+
Int32GetDatum(len));
347+
348+
ReleaseSysCache(tuple);
349+
350+
/* build text data type structre. we cannot use textin() here,
351+
since textin assumes that input string encoding is same as
352+
database encoding. */
353+
len = strlen(result) + VARHDRSZ;
354+
retval = palloc(len);
355+
VARATT_SIZEP(retval) = len;
356+
memcpy(VARDATA(retval), result, len - VARHDRSZ);
357+
358+
pfree(result);
359+
pfree(str);
360+
361+
/* free memory if allocated by the toaster */
362+
PG_FREE_IF_COPY(string, 0);
363+
364+
PG_RETURN_TEXT_P(retval);
365+
}

src/backend/parser/gram.y

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.356 2002/08/05 02:30:50 tgl Exp $
14+
* $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.357 2002/08/06 05:40:45 ishii Exp $
1515
*
1616
* HISTORY
1717
* AUTHOR DATE MAJOR EVENT
@@ -53,6 +53,7 @@
5353
#include "access/htup.h"
5454
#include "catalog/index.h"
5555
#include "catalog/namespace.h"
56+
#include "catalog/pg_conversion.h"
5657
#include "catalog/pg_type.h"
5758
#include "nodes/makefuncs.h"
5859
#include "nodes/params.h"
@@ -216,7 +217,8 @@ static void doNegateFloat(Value *v);
216217
insert_target_list, def_list, opt_indirection,
217218
group_clause, TriggerFuncArgs, select_limit,
218219
opt_select_limit, opclass_item_list, trans_options,
219-
TableFuncElementList, OptTableFuncElementList
220+
TableFuncElementList, OptTableFuncElementList,
221+
convert_args
220222

221223
%type <range> into_clause, OptTempTableName
222224

@@ -232,7 +234,7 @@ static void doNegateFloat(Value *v);
232234
%type <jtype> join_type
233235

234236
%type <list> extract_list, overlay_list, position_list
235-
%type <list> substr_list, trim_list
237+
%type <list> substr_list, trim_list, convert_list
236238
%type <ival> opt_interval
237239
%type <node> overlay_placing, substr_from, substr_for
238240

@@ -329,7 +331,7 @@ static void doNegateFloat(Value *v);
329331
CACHE, CALLED, CASCADE, CASE, CAST, CHAIN, CHAR_P,
330332
CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLASS, CLOSE,
331333
CLUSTER, COALESCE, COLLATE, COLUMN, COMMENT, COMMIT,
332-
COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, COPY, CREATE, CREATEDB,
334+
COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, CONVERT, COPY, CREATE, CREATEDB,
333335
CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME,
334336
CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE,
335337

@@ -6253,6 +6255,15 @@ c_expr: columnref { $$ = (Node *) $1; }
62536255
n->agg_distinct = FALSE;
62546256
$$ = (Node *)n;
62556257
}
6258+
| CONVERT '(' convert_list ')'
6259+
{
6260+
FuncCall *n = makeNode(FuncCall);
6261+
n->funcname = SystemFuncName("convert");
6262+
n->args = $3;
6263+
n->agg_star = FALSE;
6264+
n->agg_distinct = FALSE;
6265+
$$ = (Node *)n;
6266+
}
62566267
| select_with_parens %prec UMINUS
62576268
{
62586269
SubLink *n = makeNode(SubLink);
@@ -6418,6 +6429,48 @@ trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); }
64186429
| expr_list { $$ = $1; }
64196430
;
64206431

6432+
/* CONVERT() arguments. We accept followings:
6433+
* SQL99 syntax
6434+
* o CONVERT(TEXT string USING conversion_name)
6435+
*
6436+
* Function calls
6437+
* o CONVERT(TEXT string, NAME src_encoding_name, NAME dest_encoding_name)
6438+
* o CONVERT(TEXT string, NAME encoding_name)
6439+
*/
6440+
convert_list:
6441+
a_expr USING any_name
6442+
{
6443+
Oid oid = FindConversionByName($3);
6444+
Const *convoid = makeNode(Const);
6445+
6446+
if (!OidIsValid(oid))
6447+
{
6448+
elog(ERROR, "Conversion \"%s\" does not exist",
6449+
NameListToString($3));
6450+
}
6451+
6452+
convoid->consttype = OIDOID;
6453+
convoid->constlen = sizeof(Oid);
6454+
convoid->constvalue = oid;
6455+
convoid->constisnull = FALSE;
6456+
convoid->constbyval = TRUE;
6457+
convoid->constisset = FALSE;
6458+
convoid->constiscast = FALSE;
6459+
$$ = makeList2($1, convoid);
6460+
}
6461+
| convert_args
6462+
{
6463+
$$ = $1;
6464+
}
6465+
| /*EMPTY*/
6466+
{ $$ = NIL; }
6467+
;
6468+
6469+
convert_args: a_expr { $$ = makeList1($1); }
6470+
| convert_args ',' a_expr { $$ = lappend($1, $3); }
6471+
;
6472+
6473+
64216474
in_expr: select_with_parens
64226475
{
64236476
SubLink *n = makeNode(SubLink);

src/backend/parser/keywords.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.123 2002/07/29 22:14:11 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.124 2002/08/06 05:40:45 ishii Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -80,6 +80,7 @@ static const ScanKeyword ScanKeywords[] = {
8080
{"constraint", CONSTRAINT},
8181
{"constraints", CONSTRAINTS},
8282
{"conversion", CONVERSION_P},
83+
{"convert", CONVERT},
8384
{"copy", COPY},
8485
{"create", CREATE},
8586
{"createdb", CREATEDB},

src/backend/utils/mb/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Makefile for utils/mb
55
#
66
# IDENTIFICATION
7-
# $Header: /cvsroot/pgsql/src/backend/utils/mb/Makefile,v 1.18 2002/07/18 02:02:30 ishii Exp $
7+
# $Header: /cvsroot/pgsql/src/backend/utils/mb/Makefile,v 1.19 2002/08/06 05:40:45 ishii Exp $
88
#
99
#-------------------------------------------------------------------------
1010

@@ -24,7 +24,7 @@ clean distclean maintainer-clean:
2424

2525
SUBSYS.o: $(OBJS)
2626
@for dir in $(DIRS); do $(MAKE) -C $$dir all || exit; done
27-
$(LD) $(LDREL) $(LDOUT) SUBSYS.o $(OBJS)
27+
$(LD) $(LDREL) $(LDOUT) $@ $^
2828

2929
depend dep:
3030
$(CC) -MM $(CFLAGS) *.c >depend

0 commit comments

Comments
 (0)