Index: doc/src/sgml/func.sgml =================================================================== RCS file: /cvsroot/pgsql/doc/src/sgml/func.sgml,v retrieving revision 1.105 diff -c -r1.105 func.sgml *** doc/src/sgml/func.sgml 31 Jul 2002 02:27:28 -0000 1.105 --- doc/src/sgml/func.sgml 31 Jul 2002 05:20:09 -0000 *************** *** 858,863 **** --- 858,876 ---- + convert(string + using conversion_name) + text + Change encoding using specified conversion name. + Conversions can be defined by CREATE CONVERSION. + Also there are some pre-defined conversion names. + See for available + conversion names. + convert('PostgreSQL' using iso8859_1_to_utf8) + 'PostgreSQL' in UNICODE(UTF-8) encoding + + + lower(string) text Convert string to lower case. *************** *** 943,948 **** --- 956,1360 ---- upper('tom') TOM + + + + + + Available conversion names + + + + conversion + source encoding + destination encoding + + + + + ascii_to_utf8 + SQL_ASCII + UNICODE + + + + big5_to_euc_tw + BIG5 + EUC_TW + + + + big5_to_mic + BIG5 + MULE_INTERNAL + + + + big5_to_utf8 + BIG5 + UNICODE + + + + euc_cn_to_utf8 + EUC_CN + UNICODE + + + + euc_jp_to_mic + EUC_JP + MULE_INTERNAL + + + + euc_jp_to_sjis + EUC_JP + SJIS + + + + euc_jp_to_utf8 + EUC_JP + UNICODE + + + + euc_kr_to_utf8 + EUC_KR + UNICODE + + + + euc_tw_to_big5 + EUC_TW + BIG5 + + + + euc_tw_to_mic + EUC_TW + MULE_INTERNAL + + + + euc_tw_to_utf8 + EUC_TW + UNICODE + + + + gb18030_to_utf8 + GB18030 + UNICODE + + + + gbk_to_utf8 + GBK + UNICODE + + + + iso8859_10_to_utf8 + LATIN6 + UNICODE + + + + iso8859_13_to_utf8 + LATIN7 + UNICODE + + + + iso8859_14_to_utf8 + LATIN8 + UNICODE + + + + iso8859_15_to_utf8 + LATIN9 + UNICODE + + + + iso8859_16_to_utf8 + LATIN10 + UNICODE + + + + iso8859_1_to_utf8 + LATIN1 + UNICODE + + + + iso8859_2_to_utf8 + LATIN2 + UNICODE + + + + iso8859_3_to_utf8 + LATIN3 + UNICODE + + + + iso8859_4_to_utf8 + LATIN4 + UNICODE + + + + iso8859_5_to_utf8 + ISO_8859_5 + UNICODE + + + + iso8859_6_to_utf8 + ISO_8859_6 + UNICODE + + + + iso8859_7_to_utf8 + ISO_8859_7 + UNICODE + + + + iso8859_8_to_utf8 + ISO_8859_8 + UNICODE + + + + iso8859_9_to_utf8 + LATIN5 + UNICODE + + + + johab_to_utf8 + JOHAB + UNICODE + + + + mic_to_big5 + MULE_INTERNAL + BIG5 + + + + mic_to_euc_jp + MULE_INTERNAL + EUC_JP + + + + mic_to_euc_tw + MULE_INTERNAL + EUC_TW + + + + mic_to_sjis + MULE_INTERNAL + SJIS + + + + sjis_to_euc_jp + SJIS + EUC_JP + + + + sjis_to_mic + SJIS + MULE_INTERNAL + + + + sjis_to_utf8 + SJIS + UNICODE + + + + tcvn_to_utf8 + TCVN + UNICODE + + + + uhc_to_utf8 + UHC + UNICODE + + + + utf8_to_ascii + UNICODE + SQL_ASCII + + + + utf8_to_big5 + UNICODE + BIG5 + + + + utf8_to_euc_cn + UNICODE + EUC_CN + + + + utf8_to_euc_jp + UNICODE + EUC_JP + + + + utf8_to_euc_kr + UNICODE + EUC_KR + + + + utf8_to_euc_tw + UNICODE + EUC_TW + + + + utf8_to_gb18030 + UNICODE + GB18030 + + + + utf8_to_gbk + UNICODE + GBK + + + + utf8_to_iso8859_1 + UNICODE + LATIN1 + + + + utf8_to_iso8859_10 + UNICODE + LATIN6 + + + + utf8_to_iso8859_13 + UNICODE + LATIN7 + + + + utf8_to_iso8859_14 + UNICODE + LATIN8 + + + + utf8_to_iso8859_15 + UNICODE + LATIN9 + + + + utf8_to_iso8859_16 + UNICODE + LATIN10 + + + + utf8_to_iso8859_2 + UNICODE + LATIN2 + + + + utf8_to_iso8859_3 + UNICODE + LATIN3 + + + + utf8_to_iso8859_4 + UNICODE + LATIN4 + + + + utf8_to_iso8859_5 + UNICODE + ISO_8859_5 + + + + utf8_to_iso8859_6 + UNICODE + ISO_8859_6 + + + + utf8_to_iso8859_7 + UNICODE + ISO_8859_7 + + + + utf8_to_iso8859_8 + UNICODE + ISO_8859_8 + + + + utf8_to_iso8859_9 + UNICODE + LATIN5 + + + + utf8_to_johab + UNICODE + JOHAB + + + + utf8_to_sjis + UNICODE + SJIS + + + + utf8_to_tcvn + UNICODE + TCVN + + + + utf8_to_uhc + UNICODE + UHC + +
Index: src/backend/catalog/namespace.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/catalog/namespace.c,v retrieving revision 1.27 diff -c -r1.27 namespace.c *** src/backend/catalog/namespace.c 29 Jul 2002 23:46:35 -0000 1.27 --- src/backend/catalog/namespace.c 31 Jul 2002 05:20:12 -0000 *************** *** 1239,1244 **** --- 1239,1281 ---- } /* + * FindConversionByName - find a conversion by possibly qualified name + */ + Oid FindConversionByName(List *name) + { + char *conversion_name; + Oid namespaceId; + Oid conoid; + List *lptr; + + /* Convert list of names to a name and namespace */ + namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name); + + if (length(name) > 1) + { + /* Check we have usage rights in target namespace */ + if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK) + return InvalidOid; + + return FindConversion(conversion_name, namespaceId); + } + + recomputeNamespacePath(); + + foreach(lptr, namespaceSearchPath) + { + Oid namespaceId = (Oid) lfirsti(lptr); + + conoid = FindConversion(conversion_name, namespaceId); + if (OidIsValid(conoid)) + return conoid; + } + + /* Not found in path */ + return InvalidOid; + } + + /* * FindDefaultConversionProc - find default encoding cnnversion proc */ Oid FindDefaultConversionProc(int4 for_encoding, int4 to_encoding) Index: src/backend/catalog/pg_conversion.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/catalog/pg_conversion.c,v retrieving revision 1.3 diff -c -r1.3 pg_conversion.c *** src/backend/catalog/pg_conversion.c 25 Jul 2002 10:07:10 -0000 1.3 --- src/backend/catalog/pg_conversion.c 31 Jul 2002 05:20:12 -0000 *************** *** 228,234 **** if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) simple_heap_delete(rel, &tuple->t_self); else ! elog(ERROR, "Conversion %u does not exist", conversionOid); heap_endscan(scan); heap_close(rel, RowExclusiveLock); } --- 228,234 ---- if (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) simple_heap_delete(rel, &tuple->t_self); else ! elog(ERROR, "conversion %u does not exist", conversionOid); heap_endscan(scan); heap_close(rel, RowExclusiveLock); } *************** *** 240,286 **** * If found, returns the procedure's oid, otherwise InvalidOid. * --------------- */ - #ifdef NOT_USED - Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding) - { - Relation rel; - HeapScanDesc scan; - ScanKeyData scanKeyData; - HeapTuple tuple; - Form_pg_conversion body; - Oid proc = InvalidOid; - - /* Check we have usage rights in target namespace */ - if (pg_namespace_aclcheck(name_space, GetUserId(), ACL_USAGE) != ACLCHECK_OK) - return InvalidOid; - - ScanKeyEntryInitialize(&scanKeyData, - 0, - Anum_pg_conversion_connamespace, - F_OIDEQ, - ObjectIdGetDatum(name_space)); - - rel = heap_openr(ConversionRelationName, AccessShareLock); - scan = heap_beginscan(rel, SnapshotNow, - 1, &scanKeyData); - - while (HeapTupleIsValid(tuple = heap_getnext(scan, ForwardScanDirection))) - { - body = (Form_pg_conversion)GETSTRUCT(tuple); - if (body->conforencoding == for_encoding && - body->contoencoding == to_encoding && - body->condefault == TRUE) - { - proc = body->conproc; - break; - } - } - heap_endscan(scan); - heap_close(rel, AccessShareLock); - return proc; - } - #endif - Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding) { CatCList *catlist; --- 240,245 ---- *************** *** 316,349 **** /* ---------------- * FindConversionByName * ! * Find conversion proc by possibly qualified conversion name. * --------------- */ ! Oid FindConversionByName(List *name) { HeapTuple tuple; - char *conversion_name; - Oid namespaceId; Oid procoid; AclResult aclresult; ! /* Convert list of names to a name and namespace */ ! namespaceId = QualifiedNameGetCreationNamespace(name, &conversion_name); ! ! /* Check we have usage rights in target namespace */ ! if (pg_namespace_aclcheck(namespaceId, GetUserId(), ACL_USAGE) != ACLCHECK_OK) ! return InvalidOid; ! ! /* search pg_conversion by namespaceId and conversion name */ tuple = SearchSysCache(CONNAMESP, ! PointerGetDatum(conversion_name), ! ObjectIdGetDatum(namespaceId), 0,0); if (!HeapTupleIsValid(tuple)) return InvalidOid; - procoid = ((Form_pg_conversion)GETSTRUCT(tuple))->conproc; ReleaseSysCache(tuple); --- 275,301 ---- /* ---------------- * FindConversionByName * ! * Find conversion by namespace and conversion name. ! * Returns conversion oid. * --------------- */ ! Oid FindConversion(const char *conname, Oid connamespace) { HeapTuple tuple; Oid procoid; + Oid conoid; AclResult aclresult; ! /* search pg_conversion by connamespace and conversion name */ tuple = SearchSysCache(CONNAMESP, ! PointerGetDatum(conname), ! ObjectIdGetDatum(connamespace), 0,0); if (!HeapTupleIsValid(tuple)) return InvalidOid; procoid = ((Form_pg_conversion)GETSTRUCT(tuple))->conproc; + conoid = HeapTupleGetOid(tuple); ReleaseSysCache(tuple); *************** *** 352,357 **** if (aclresult != ACLCHECK_OK) return InvalidOid; ! return procoid; } --- 304,372 ---- if (aclresult != ACLCHECK_OK) return InvalidOid; ! return conoid; } + /* + * Execute SQL99's CONVERT function. + * + * CONVERT + * USING + * + * TEXT convert3(TEXT string, OID conversion_oid); + */ + Datum + pg_convert3(PG_FUNCTION_ARGS) + { + text *string = PG_GETARG_TEXT_P(0); + Oid convoid = PG_GETARG_OID(1); + HeapTuple tuple; + Form_pg_conversion body; + text *retval; + unsigned char *str; + unsigned char *result; + int len; + + if (!OidIsValid(convoid)) + elog(ERROR, "Conversion does not exist"); + + /* make sure that source string is null terminated */ + len = VARSIZE(string) - VARHDRSZ; + str = palloc(len + 1); + memcpy(str, VARDATA(string), len); + *(str + len) = '\0'; + + tuple = SearchSysCache(CONOID, + ObjectIdGetDatum(convoid), + 0,0,0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "Conversion %u search from syscache failed", convoid); + + result = palloc(len * 4 + 1); + + body = (Form_pg_conversion)GETSTRUCT(tuple); + OidFunctionCall5(body->conproc, + Int32GetDatum(body->conforencoding), + Int32GetDatum(body->contoencoding), + CStringGetDatum(str), + CStringGetDatum(result), + Int32GetDatum(len)); + + ReleaseSysCache(tuple); + + /* build text data type structre. we cannot use textin() here, + since textin assumes that input string encoding is same as + database encoding. */ + len = strlen(result) + VARHDRSZ; + retval = palloc(len); + VARATT_SIZEP(retval) = len; + memcpy(VARDATA(retval), result, len - VARHDRSZ); + + pfree(result); + pfree(str); + + /* free memory if allocated by the toaster */ + PG_FREE_IF_COPY(string, 0); + + PG_RETURN_TEXT_P(retval); + } Index: src/backend/parser/gram.y =================================================================== RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v retrieving revision 2.351 diff -c -r2.351 gram.y *** src/backend/parser/gram.y 30 Jul 2002 16:55:44 -0000 2.351 --- src/backend/parser/gram.y 31 Jul 2002 05:20:21 -0000 *************** *** 53,58 **** --- 53,59 ---- #include "access/htup.h" #include "catalog/index.h" #include "catalog/namespace.h" + #include "catalog/pg_conversion.h" #include "catalog/pg_type.h" #include "nodes/makefuncs.h" #include "nodes/params.h" *************** *** 218,224 **** target_list, update_target_list, insert_column_list, insert_target_list, def_list, opt_indirection, group_clause, TriggerFuncArgs, select_limit, ! opt_select_limit, opclass_item_list %type into_clause, OptTempTableName --- 219,225 ---- target_list, update_target_list, insert_column_list, insert_target_list, def_list, opt_indirection, group_clause, TriggerFuncArgs, select_limit, ! opt_select_limit, opclass_item_list, expr_list2 %type into_clause, OptTempTableName *************** *** 234,240 **** %type join_type %type extract_list, overlay_list, position_list ! %type substr_list, trim_list %type opt_interval %type overlay_placing, substr_from, substr_for --- 235,241 ---- %type join_type %type extract_list, overlay_list, position_list ! %type substr_list, trim_list, convert_list %type opt_interval %type overlay_placing, substr_from, substr_for *************** *** 328,334 **** CACHE, CALLED, CASCADE, CASE, CAST, CHAIN, CHAR_P, CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLASS, CLOSE, CLUSTER, COALESCE, COLLATE, COLUMN, COMMENT, COMMIT, ! COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, COPY, CREATE, CREATEDB, CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE, --- 329,336 ---- CACHE, CALLED, CASCADE, CASE, CAST, CHAIN, CHAR_P, CHARACTER, CHARACTERISTICS, CHECK, CHECKPOINT, CLASS, CLOSE, CLUSTER, COALESCE, COLLATE, COLUMN, COMMENT, COMMIT, ! COMMITTED, CONSTRAINT, CONSTRAINTS, CONVERSION_P, CONVERT_P, ! COPY, CREATE, CREATEDB, CREATEUSER, CROSS, CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP, CURRENT_USER, CURSOR, CYCLE, *************** *** 6085,6090 **** --- 6087,6101 ---- n->agg_distinct = FALSE; $$ = (Node *)n; } + | CONVERT_P '(' convert_list ')' + { + FuncCall *n = makeNode(FuncCall); + n->funcname = SystemFuncName("convert"); + n->args = $3; + n->agg_star = FALSE; + n->agg_distinct = FALSE; + $$ = (Node *)n; + } | select_with_parens %prec UMINUS { SubLink *n = makeNode(SubLink); *************** *** 6237,6242 **** --- 6248,6294 ---- trim_list: a_expr FROM expr_list { $$ = lappend($3, $1); } | FROM expr_list { $$ = $2; } | expr_list { $$ = $1; } + ; + + /* CONVERT() arguments. We accept followings: + * SQL99 syntax + * o CONVERT(TEXT string USING conversion_name) + * + * Function calls + * o CONVERT(TEXT string, NAME src_encoding_name, NAME dest_encoding_name) + * o CONVERT(TEXT string, NAME encoding_name) + */ + convert_list: + a_expr USING any_name + { + Oid oid = FindConversionByName($3); + Const *convoid = makeNode(Const); + + if (!OidIsValid(oid)) + { + elog(ERROR, "Conversion \"%s\" does not exist", + NameListToString($3)); + } + + convoid->consttype = OIDOID; + convoid->constlen = sizeof(Oid); + convoid->constvalue = oid; + convoid->constisnull = FALSE; + convoid->constbyval = TRUE; + convoid->constisset = FALSE; + convoid->constiscast = FALSE; + $$ = makeList2($1, convoid); + } + | expr_list2 + { + $$ = $1; + } + | /*EMPTY*/ + { $$ = NIL; } + ; + + expr_list2: a_expr { $$ = makeList1($1); } + | expr_list2 ',' a_expr { $$ = lappend($1, $3); } ; in_expr: select_with_parens Index: src/backend/parser/keywords.c =================================================================== RCS file: /cvsroot/pgsql/src/backend/parser/keywords.c,v retrieving revision 1.123 diff -c -r1.123 keywords.c *** src/backend/parser/keywords.c 29 Jul 2002 22:14:11 -0000 1.123 --- src/backend/parser/keywords.c 31 Jul 2002 05:20:21 -0000 *************** *** 80,85 **** --- 80,86 ---- {"constraint", CONSTRAINT}, {"constraints", CONSTRAINTS}, {"conversion", CONVERSION_P}, + {"convert", CONVERT_P}, {"copy", COPY}, {"create", CREATE}, {"createdb", CREATEDB}, Index: src/include/catalog/namespace.h =================================================================== RCS file: /cvsroot/pgsql/src/include/catalog/namespace.h,v retrieving revision 1.17 diff -c -r1.17 namespace.h *** src/include/catalog/namespace.h 29 Jul 2002 23:46:35 -0000 1.17 --- src/include/catalog/namespace.h 31 Jul 2002 05:20:23 -0000 *************** *** 80,85 **** --- 80,86 ---- extern void PushSpecialNamespace(Oid namespaceId); extern void PopSpecialNamespace(Oid namespaceId); + extern Oid FindConversionByName(List *conname); extern Oid FindDefaultConversionProc(int4 for_encoding, int4 to_encoding); /* initialization & transaction cleanup code */ Index: src/include/catalog/pg_conversion.h =================================================================== RCS file: /cvsroot/pgsql/src/include/catalog/pg_conversion.h,v retrieving revision 1.2 diff -c -r1.2 pg_conversion.h *** src/include/catalog/pg_conversion.h 25 Jul 2002 10:07:13 -0000 1.2 --- src/include/catalog/pg_conversion.h 31 Jul 2002 05:20:23 -0000 *************** *** 90,96 **** extern void ConversionDrop(const char *conname, Oid connamespace, int32 conowner, DropBehavior behavior); extern void RemoveConversionById(Oid conversionOid); ! extern Oid FindDefaultConversion(Oid name_space, int4 for_encoding, int4 to_encoding); ! extern Oid FindConversionByName(List *conname); #endif /* PG_CONVERSION_H */ --- 90,98 ---- extern void ConversionDrop(const char *conname, Oid connamespace, int32 conowner, DropBehavior behavior); extern void RemoveConversionById(Oid conversionOid); ! extern Oid FindConversion(const char *conname, Oid connamespace); ! extern Oid FindDefaultConversion(Oid connamespace, int4 for_encoding, int4 to_encoding); ! ! extern Datum pg_convert3(PG_FUNCTION_ARGS); #endif /* PG_CONVERSION_H */ Index: src/include/catalog/pg_proc.h =================================================================== RCS file: /cvsroot/pgsql/src/include/catalog/pg_proc.h,v retrieving revision 1.248 diff -c -r1.248 pg_proc.h *** src/include/catalog/pg_proc.h 31 Jul 2002 01:49:13 -0000 1.248 --- src/include/catalog/pg_proc.h 31 Jul 2002 05:20:28 -0000 *************** *** 2149,2154 **** --- 2149,2157 ---- DATA(insert OID = 1813 ( convert PGNSP PGUID 12 f f t f s 3 25 "25 19 19" pg_convert2 - _null_ )); DESCR("convert string with specified encoding names"); + DATA(insert OID = 90 ( convert PGNSP PGUID 12 f f t f s 2 25 "25 26" pg_convert3 - _null_ )); + DESCR("convert string with specified conversion oid"); + DATA(insert OID = 1264 ( pg_char_to_encoding PGNSP PGUID 12 f f t f s 1 23 "19" PG_char_to_encoding - _null_ )); DESCR("convert encoding name to encoding id");