Приложение C. Ключевые слова SQL

В Таблице C.1 перечислены все слова, которые являются ключевыми в стандарте SQL и в PostgreSQL 17.4. Общее описание ключевых слов можно найти в Подразделе 4.1.1. (Для экономии места в таблицу включены только две последние версии стандарта SQL и SQL-92 для исторического сравнения. Отличия между ними и другими промежуточными версиями стандарта невелики.)

В SQL есть различие между зарезервированными и незарезервированными ключевыми словами. Согласно стандарту, действительно ключевыми словами являются только зарезервированные слова; они не могут быть идентификаторами. Незарезервированные ключевые слова имеют особое значение только в определённых контекстах и могут быть идентификаторами в других. Большинство незарезервированных ключевых слов на самом деле представляют имена встроенных таблиц и функций, определённых в SQL. Концепция незарезервированных ключевых слов собственно введена только для того, чтобы показать, что эти слова имеют некоторое предопределённое значение в отдельных контекстах.

В PostgreSQL анализатор SQL сталкивается с дополнительными сложностями. Ему приходится иметь дело с несколькими различными классами элементов языка, начиная с тех, что никогда не могут использоваться как идентификаторы, и заканчивая теми, которые не имеют никакого специального значения для анализатора, а считаются обычными идентификаторами. (Последнее обычно относится к функциям, описанным в SQL.) Даже зарезервированные ключевые слова не полностью зарезервированы в PostgreSQL, а могут использоваться в качестве меток столбцов (например, можно написать SELECT 55 AS CHECK, хотя CHECK и является зарезервированным ключевым словом).

В Таблице C.1, в столбце PostgreSQL мы даём пометку «не зарезервировано» тем ключевым словам, которые явно известны анализатору запросов, но их можно использовать в качестве имени столбца или таблицы. Некоторые ключевые слова, которые недопустимы в качестве имени функции или типа данных, но в остальном не отличаются от незарезервированных слов, помечены соответственно. (Большинство из этих слов представляют встроенные функции или типы данных со специальным синтаксисом. Функции или типы с таким именем существуют, но пользователь не может их переопределить.) Метка «зарезервировано» даётся тем словам, которые не могут быть именами столбцов или таблиц. Некоторые зарезервированные ключевые слова могут быть именами функций или типов данных; это также отмечается в таблице. Если такой пометки нет, зарезервированное слово допускается только в качестве метки столбца. Пустое содержимое ячейки означает, что PostgreSQL воспринимает это слово как обычный идентификатор.

Кроме того, хотя большинство ключевых слов можно использовать как «открытые» метки столбцов, не добавляя перед ними AS (как описано в Подразделе 7.3.2), есть ряд исключений — перед такими ключевыми словами нужно добавлять AS во избежание двусмысленности. В этой таблице они имеют пометку «requires AS».

Вообще, если вы сталкиваетесь с разнообразными ошибками разбора команд, использующих в качестве идентификаторов какие-либо из перечисленных ключевых слов, попробуйте для решения проблемы заключить идентификатор в кавычки.

Изучая Таблицу C.1, важно понимать, что отсутствие какого-либо ключевого слова в списке зарезервированных в PostgreSQL не означает, что функциональность, связанная с этим словом, не реализована. И наоборот, присутствие ключевого слова не обязательно говорит о наличии соответствующей функциональности.

Таблица C.1. SQL Key Words

Key WordPostgreSQLSQL:2023SQL:2016SQL-92
A non-reservednon-reserved 
ABORTnon-reserved   
ABS reservedreserved 
ABSENTnon-reservedreservedreserved 
ABSOLUTEnon-reservednon-reservednon-reservedreserved
ACCESSnon-reserved   
ACCORDING non-reservednon-reserved 
ACOS reservedreserved 
ACTIONnon-reservednon-reservednon-reservedreserved
ADA non-reservednon-reservednon-reserved
ADDnon-reservednon-reservednon-reservedreserved
ADMINnon-reservednon-reservednon-reserved 
AFTERnon-reservednon-reservednon-reserved 
AGGREGATEnon-reserved   
ALLreservedreservedreservedreserved
ALLOCATE reservedreservedreserved
ALSOnon-reserved   
ALTERnon-reservedreservedreservedreserved
ALWAYSnon-reservednon-reservednon-reserved 
ANALYSEreserved   
ANALYZEreserved   
ANDreservedreservedreservedreserved
ANYreservedreservedreservedreserved
ANY_VALUE reserved  
ARE reservedreservedreserved
ARRAYreserved, requires ASreservedreserved 
ARRAY_AGG reservedreserved 
ARRAY_​MAX_​CARDINALITY reservedreserved 
ASreserved, requires ASreservedreservedreserved
ASCreservednon-reservednon-reservedreserved
ASENSITIVEnon-reservedreservedreserved 
ASIN reservedreserved 
ASSERTIONnon-reservednon-reservednon-reservedreserved
ASSIGNMENTnon-reservednon-reservednon-reserved 
ASYMMETRICreservedreservedreserved 
ATnon-reservedreservedreservedreserved
ATAN reservedreserved 
ATOMICnon-reservedreservedreserved 
ATTACHnon-reserved   
ATTRIBUTEnon-reservednon-reservednon-reserved 
ATTRIBUTES non-reservednon-reserved 
AUTHORIZATIONreserved (can be function or type)reservedreservedreserved
AVG reservedreservedreserved
BACKWARDnon-reserved   
BASE64 non-reservednon-reserved 
BEFOREnon-reservednon-reservednon-reserved 
BEGINnon-reservedreservedreservedreserved
BEGIN_FRAME reservedreserved 
BEGIN_PARTITION reservedreserved 
BERNOULLI non-reservednon-reserved 
BETWEENnon-reserved (cannot be function or type)reservedreservedreserved
BIGINTnon-reserved (cannot be function or type)reservedreserved 
BINARYreserved (can be function or type)reservedreserved 
BITnon-reserved (cannot be function or type)  reserved
BIT_LENGTH   reserved
BLOB reservedreserved 
BLOCKED non-reservednon-reserved 
BOM non-reservednon-reserved 
BOOLEANnon-reserved (cannot be function or type)reservedreserved 
BOTHreservedreservedreservedreserved
BREADTHnon-reservednon-reservednon-reserved 
BTRIM reserved  
BYnon-reservedreservedreservedreserved
C non-reservednon-reservednon-reserved
CACHEnon-reserved   
CALLnon-reservedreservedreserved 
CALLEDnon-reservedreservedreserved 
CARDINALITY reservedreserved 
CASCADEnon-reservednon-reservednon-reservedreserved
CASCADEDnon-reservedreservedreservedreserved
CASEreservedreservedreservedreserved
CASTreservedreservedreservedreserved
CATALOGnon-reservednon-reservednon-reservedreserved
CATALOG_NAME non-reservednon-reservednon-reserved
CEIL reservedreserved 
CEILING reservedreserved 
CHAINnon-reservednon-reservednon-reserved 
CHAINING non-reservednon-reserved 
CHARnon-reserved (cannot be function or type), requires ASreservedreservedreserved
CHARACTERnon-reserved (cannot be function or type), requires ASreservedreservedreserved
CHARACTERISTICSnon-reservednon-reservednon-reserved 
CHARACTERS non-reservednon-reserved 
CHARACTER_LENGTH reservedreservedreserved
CHARACTER_​SET_​CATALOG non-reservednon-reservednon-reserved
CHARACTER_SET_NAME non-reservednon-reservednon-reserved
CHARACTER_SET_SCHEMA non-reservednon-reservednon-reserved
CHAR_LENGTH reservedreservedreserved
CHECKreservedreservedreservedreserved
CHECKPOINTnon-reserved   
CLASSnon-reserved   
CLASSIFIER reservedreserved 
CLASS_ORIGIN non-reservednon-reservednon-reserved
CLOB reservedreserved 
CLOSEnon-reservedreservedreservedreserved
CLUSTERnon-reserved   
COALESCEnon-reserved (cannot be function or type)reservedreservedreserved
COBOL non-reservednon-reservednon-reserved
COLLATEreservedreservedreservedreserved
COLLATIONreserved (can be function or type)non-reservednon-reservedreserved
COLLATION_CATALOG non-reservednon-reservednon-reserved
COLLATION_NAME non-reservednon-reservednon-reserved
COLLATION_SCHEMA non-reservednon-reservednon-reserved
COLLECT reservedreserved 
COLUMNreservedreservedreservedreserved
COLUMNSnon-reservednon-reservednon-reserved 
COLUMN_NAME non-reservednon-reservednon-reserved
COMMAND_FUNCTION non-reservednon-reservednon-reserved
COMMAND_​FUNCTION_​CODE non-reservednon-reserved 
COMMENTnon-reserved   
COMMENTSnon-reserved   
COMMITnon-reservedreservedreservedreserved
COMMITTEDnon-reservednon-reservednon-reservednon-reserved
COMPRESSIONnon-reserved   
CONCURRENTLYreserved (can be function or type)   
CONDITION reservedreserved 
CONDITIONALnon-reservednon-reservednon-reserved 
CONDITION_NUMBER non-reservednon-reservednon-reserved
CONFIGURATIONnon-reserved   
CONFLICTnon-reserved   
CONNECT reservedreservedreserved
CONNECTIONnon-reservednon-reservednon-reservedreserved
CONNECTION_NAME non-reservednon-reservednon-reserved
CONSTRAINTreservedreservedreservedreserved
CONSTRAINTSnon-reservednon-reservednon-reservedreserved
CONSTRAINT_CATALOG non-reservednon-reservednon-reserved
CONSTRAINT_NAME non-reservednon-reservednon-reserved
CONSTRAINT_SCHEMA non-reservednon-reservednon-reserved
CONSTRUCTOR non-reservednon-reserved 
CONTAINS reservedreserved 
CONTENTnon-reservednon-reservednon-reserved 
CONTINUEnon-reservednon-reservednon-reservedreserved
CONTROL non-reservednon-reserved 
CONVERSIONnon-reserved   
CONVERT reservedreservedreserved
COPARTITION non-reserved  
COPYnon-reservedreservedreserved 
CORR reservedreserved 
CORRESPONDING reservedreservedreserved
COS reservedreserved 
COSH reservedreserved 
COSTnon-reserved   
COUNT reservedreservedreserved
COVAR_POP reservedreserved 
COVAR_SAMP reservedreserved 
CREATEreserved, requires ASreservedreservedreserved
CROSSreserved (can be function or type)reservedreservedreserved
CSVnon-reserved   
CUBEnon-reservedreservedreserved 
CUME_DIST reservedreserved 
CURRENTnon-reservedreservedreservedreserved
CURRENT_CATALOGreservedreservedreserved 
CURRENT_DATEreservedreservedreservedreserved
CURRENT_​DEFAULT_​TRANSFORM_​GROUP reservedreserved 
CURRENT_PATH reservedreserved 
CURRENT_ROLEreservedreservedreserved 
CURRENT_ROW reservedreserved 
CURRENT_SCHEMAreserved (can be function or type)reservedreserved 
CURRENT_TIMEreservedreservedreservedreserved
CURRENT_TIMESTAMPreservedreservedreservedreserved
CURRENT_​TRANSFORM_​GROUP_​FOR_​TYPE reservedreserved 
CURRENT_USERreservedreservedreservedreserved
CURSORnon-reservedreservedreservedreserved
CURSOR_NAME non-reservednon-reservednon-reserved
CYCLEnon-reservedreservedreserved 
DATAnon-reservednon-reservednon-reservednon-reserved
DATABASEnon-reserved   
DATALINK reservedreserved 
DATE reservedreservedreserved
DATETIME_​INTERVAL_​CODE non-reservednon-reservednon-reserved
DATETIME_​INTERVAL_​PRECISION non-reservednon-reservednon-reserved
DAYnon-reserved, requires ASreservedreservedreserved
DB non-reservednon-reserved 
DEALLOCATEnon-reservedreservedreservedreserved
DECnon-reserved (cannot be function or type)reservedreservedreserved
DECFLOAT reservedreserved 
DECIMALnon-reserved (cannot be function or type)reservedreservedreserved
DECLAREnon-reservedreservedreservedreserved
DEFAULTreservedreservedreservedreserved
DEFAULTSnon-reservednon-reservednon-reserved 
DEFERRABLEreservednon-reservednon-reservedreserved
DEFERREDnon-reservednon-reservednon-reservedreserved
DEFINE reservedreserved 
DEFINED non-reservednon-reserved 
DEFINERnon-reservednon-reservednon-reserved 
DEGREE non-reservednon-reserved 
DELETEnon-reservedreservedreservedreserved
DELIMITERnon-reserved   
DELIMITERSnon-reserved   
DENSE_RANK reservedreserved 
DEPENDSnon-reserved   
DEPTHnon-reservednon-reservednon-reserved 
DEREF reservedreserved 
DERIVED non-reservednon-reserved 
DESCreservednon-reservednon-reservedreserved
DESCRIBE reservedreservedreserved
DESCRIPTOR non-reservednon-reservedreserved
DETACHnon-reserved   
DETERMINISTIC reservedreserved 
DIAGNOSTICS non-reservednon-reservedreserved
DICTIONARYnon-reserved   
DISABLEnon-reserved   
DISCARDnon-reserved   
DISCONNECT reservedreservedreserved
DISPATCH non-reservednon-reserved 
DISTINCTreservedreservedreservedreserved
DLNEWCOPY reservedreserved 
DLPREVIOUSCOPY reservedreserved 
DLURLCOMPLETE reservedreserved 
DLURLCOMPLETEONLY reservedreserved 
DLURLCOMPLETEWRITE reservedreserved 
DLURLPATH reservedreserved 
DLURLPATHONLY reservedreserved 
DLURLPATHWRITE reservedreserved 
DLURLSCHEME reservedreserved 
DLURLSERVER reservedreserved 
DLVALUE reservedreserved 
DOreserved   
DOCUMENTnon-reservednon-reservednon-reserved 
DOMAINnon-reservednon-reservednon-reservedreserved
DOUBLEnon-reservedreservedreservedreserved
DROPnon-reservedreservedreservedreserved
DYNAMIC reservedreserved 
DYNAMIC_FUNCTION non-reservednon-reservednon-reserved
DYNAMIC_​FUNCTION_​CODE non-reservednon-reserved 
EACHnon-reservedreservedreserved 
ELEMENT reservedreserved 
ELSEreservedreservedreservedreserved
EMPTYnon-reservedreservedreserved 
ENABLEnon-reserved   
ENCODINGnon-reservednon-reservednon-reserved 
ENCRYPTEDnon-reserved   
ENDreservedreservedreservedreserved
END-EXEC reservedreservedreserved
END_FRAME reservedreserved 
END_PARTITION reservedreserved 
ENFORCED non-reservednon-reserved 
ENUMnon-reserved   
EQUALS reservedreserved 
ERRORnon-reservednon-reservednon-reserved 
ESCAPEnon-reservedreservedreservedreserved
EVENTnon-reserved   
EVERY reservedreserved 
EXCEPTreserved, requires ASreservedreservedreserved
EXCEPTION   reserved
EXCLUDEnon-reservednon-reservednon-reserved 
EXCLUDINGnon-reservednon-reservednon-reserved 
EXCLUSIVEnon-reserved   
EXEC reservedreservedreserved
EXECUTEnon-reservedreservedreservedreserved
EXISTSnon-reserved (cannot be function or type)reservedreservedreserved
EXP reservedreserved 
EXPLAINnon-reserved   
EXPRESSIONnon-reservednon-reservednon-reserved 
EXTENSIONnon-reserved   
EXTERNALnon-reservedreservedreservedreserved
EXTRACTnon-reserved (cannot be function or type)reservedreservedreserved
FALSEreservedreservedreservedreserved
FAMILYnon-reserved   
FETCHreserved, requires ASreservedreservedreserved
FILE non-reservednon-reserved 
FILTERnon-reserved, requires ASreservedreserved 
FINAL non-reservednon-reserved 
FINALIZEnon-reserved   
FINISH non-reservednon-reserved 
FIRSTnon-reservednon-reservednon-reservedreserved
FIRST_VALUE reservedreserved 
FLAG non-reservednon-reserved 
FLOATnon-reserved (cannot be function or type)reservedreservedreserved
FLOOR reservedreserved 
FOLLOWINGnon-reservednon-reservednon-reserved 
FORreserved, requires ASreservedreservedreserved
FORCEnon-reserved   
FOREIGNreservedreservedreservedreserved
FORMATnon-reservednon-reservednon-reserved 
FORTRAN non-reservednon-reservednon-reserved
FORWARDnon-reserved   
FOUND non-reservednon-reservedreserved
FRAME_ROW reservedreserved 
FREE reservedreserved 
FREEZEreserved (can be function or type)   
FROMreserved, requires ASreservedreservedreserved
FS non-reservednon-reserved 
FULFILL non-reservednon-reserved 
FULLreserved (can be function or type)reservedreservedreserved
FUNCTIONnon-reservedreservedreserved 
FUNCTIONSnon-reserved   
FUSION reservedreserved 
G non-reservednon-reserved 
GENERAL non-reservednon-reserved 
GENERATEDnon-reservednon-reservednon-reserved 
GET reservedreservedreserved
GLOBALnon-reservedreservedreservedreserved
GO non-reservednon-reservedreserved
GOTO non-reservednon-reservedreserved
GRANTreserved, requires ASreservedreservedreserved
GRANTEDnon-reservednon-reservednon-reserved 
GREATESTnon-reserved (cannot be function or type)reserved  
GROUPreserved, requires ASreservedreservedreserved
GROUPINGnon-reserved (cannot be function or type)reservedreserved 
GROUPSnon-reservedreservedreserved 
HANDLERnon-reserved   
HAVINGreserved, requires ASreservedreservedreserved
HEADERnon-reserved   
HEX non-reservednon-reserved 
HIERARCHY non-reservednon-reserved 
HOLDnon-reservedreservedreserved 
HOURnon-reserved, requires ASreservedreservedreserved
ID non-reservednon-reserved 
IDENTITYnon-reservedreservedreservedreserved
IFnon-reserved   
IGNORE non-reservednon-reserved 
ILIKEreserved (can be function or type)   
IMMEDIATEnon-reservednon-reservednon-reservedreserved
IMMEDIATELY non-reservednon-reserved 
IMMUTABLEnon-reserved   
IMPLEMENTATION non-reservednon-reserved 
IMPLICITnon-reserved   
IMPORTnon-reservedreservedreserved 
INreservedreservedreservedreserved
INCLUDEnon-reserved   
INCLUDINGnon-reservednon-reservednon-reserved 
INCREMENTnon-reservednon-reservednon-reserved 
INDENTnon-reservednon-reservednon-reserved 
INDEXnon-reserved   
INDEXESnon-reserved   
INDICATOR reservedreservedreserved
INHERITnon-reserved   
INHERITSnon-reserved   
INITIAL reservedreserved 
INITIALLYreservednon-reservednon-reservedreserved
INLINEnon-reserved   
INNERreserved (can be function or type)reservedreservedreserved
INOUTnon-reserved (cannot be function or type)reservedreserved 
INPUTnon-reservednon-reservednon-reservedreserved
INSENSITIVEnon-reservedreservedreservedreserved
INSERTnon-reservedreservedreservedreserved
INSTANCE non-reservednon-reserved 
INSTANTIABLE non-reservednon-reserved 
INSTEADnon-reservednon-reservednon-reserved 
INTnon-reserved (cannot be function or type)reservedreservedreserved
INTEGERnon-reserved (cannot be function or type)reservedreservedreserved
INTEGRITY non-reservednon-reserved 
INTERSECTreserved, requires ASreservedreservedreserved
INTERSECTION reservedreserved 
INTERVALnon-reserved (cannot be function or type)reservedreservedreserved
INTOreserved, requires ASreservedreservedreserved
INVOKERnon-reservednon-reservednon-reserved 
ISreserved (can be function or type)reservedreservedreserved
ISNULLreserved (can be function or type), requires AS   
ISOLATIONnon-reservednon-reservednon-reservedreserved
JOINreserved (can be function or type)reservedreservedreserved
JSONnon-reserved (cannot be function or type)reserved  
JSON_ARRAYnon-reserved (cannot be function or type)reservedreserved 
JSON_ARRAYAGGnon-reserved (cannot be function or type)reservedreserved 
JSON_EXISTSnon-reserved (cannot be function or type)reservedreserved 
JSON_OBJECTnon-reserved (cannot be function or type)reservedreserved 
JSON_OBJECTAGGnon-reserved (cannot be function or type)reservedreserved 
JSON_QUERYnon-reserved (cannot be function or type)reservedreserved 
JSON_SCALARnon-reserved (cannot be function or type)reserved  
JSON_SERIALIZEnon-reserved (cannot be function or type)reserved  
JSON_TABLEnon-reserved (cannot be function or type)reservedreserved 
JSON_TABLE_PRIMITIVE reservedreserved 
JSON_VALUEnon-reserved (cannot be function or type)reservedreserved 
K non-reservednon-reserved 
KEEPnon-reservednon-reservednon-reserved 
KEYnon-reservednon-reservednon-reservedreserved
KEYSnon-reservednon-reservednon-reserved 
KEY_MEMBER non-reservednon-reserved 
KEY_TYPE non-reservednon-reserved 
LABELnon-reserved   
LAG reservedreserved 
LANGUAGEnon-reservedreservedreservedreserved
LARGEnon-reservedreservedreserved 
LASTnon-reservednon-reservednon-reservedreserved
LAST_VALUE reservedreserved 
LATERALreservedreservedreserved 
LEAD reservedreserved 
LEADINGreservedreservedreservedreserved
LEAKPROOFnon-reserved   
LEASTnon-reserved (cannot be function or type)reserved  
LEFTreserved (can be function or type)reservedreservedreserved
LENGTH non-reservednon-reservednon-reserved
LEVELnon-reservednon-reservednon-reservedreserved
LIBRARY non-reservednon-reserved 
LIKEreserved (can be function or type)reservedreservedreserved
LIKE_REGEX reservedreserved 
LIMITreserved, requires ASnon-reservednon-reserved 
LINK non-reservednon-reserved 
LISTAGG reservedreserved 
LISTENnon-reserved   
LN reservedreserved 
LOADnon-reserved   
LOCALnon-reservedreservedreservedreserved
LOCALTIMEreservedreservedreserved 
LOCALTIMESTAMPreservedreservedreserved 
LOCATIONnon-reservednon-reservednon-reserved 
LOCATOR non-reservednon-reserved 
LOCKnon-reserved   
LOCKEDnon-reserved   
LOG reservedreserved 
LOG10 reservedreserved 
LOGGEDnon-reserved   
LOWER reservedreservedreserved
LPAD reserved  
LTRIM reserved  
M non-reservednon-reserved 
MAP non-reservednon-reserved 
MAPPINGnon-reservednon-reservednon-reserved 
MATCHnon-reservedreservedreservedreserved
MATCHEDnon-reservednon-reservednon-reserved 
MATCHES reservedreserved 
MATCH_NUMBER reservedreserved 
MATCH_RECOGNIZE reservedreserved 
MATERIALIZEDnon-reserved   
MAX reservedreservedreserved
MAXVALUEnon-reservednon-reservednon-reserved 
MEASURES non-reservednon-reserved 
MEMBER reservedreserved 
MERGEnon-reservedreservedreserved 
MERGE_ACTIONnon-reserved (cannot be function or type)   
MESSAGE_LENGTH non-reservednon-reservednon-reserved
MESSAGE_OCTET_LENGTH non-reservednon-reservednon-reserved
MESSAGE_TEXT non-reservednon-reservednon-reserved
METHODnon-reservedreservedreserved 
MIN reservedreservedreserved
MINUTEnon-reserved, requires ASreservedreservedreserved
MINVALUEnon-reservednon-reservednon-reserved 
MOD reservedreserved 
MODEnon-reserved   
MODIFIES reservedreserved 
MODULE reservedreservedreserved
MONTHnon-reserved, requires ASreservedreservedreserved
MORE non-reservednon-reservednon-reserved
MOVEnon-reserved   
MULTISET reservedreserved 
MUMPS non-reservednon-reservednon-reserved
NAMEnon-reservednon-reservednon-reservednon-reserved
NAMESnon-reservednon-reservednon-reservedreserved
NAMESPACE non-reservednon-reserved 
NATIONALnon-reserved (cannot be function or type)reservedreservedreserved
NATURALreserved (can be function or type)reservedreservedreserved
NCHARnon-reserved (cannot be function or type)reservedreservedreserved
NCLOB reservedreserved 
NESTEDnon-reservednon-reservednon-reserved 
NESTING non-reservednon-reserved 
NEWnon-reservedreservedreserved 
NEXTnon-reservednon-reservednon-reservedreserved
NFCnon-reservednon-reservednon-reserved 
NFDnon-reservednon-reservednon-reserved 
NFKCnon-reservednon-reservednon-reserved 
NFKDnon-reservednon-reservednon-reserved 
NIL non-reservednon-reserved 
NOnon-reservedreservedreservedreserved
NONEnon-reserved (cannot be function or type)reservedreserved 
NORMALIZEnon-reserved (cannot be function or type)reservedreserved 
NORMALIZEDnon-reservednon-reservednon-reserved 
NOTreservedreservedreservedreserved
NOTHINGnon-reserved   
NOTIFYnon-reserved   
NOTNULLreserved (can be function or type), requires AS   
NOWAITnon-reserved   
NTH_VALUE reservedreserved 
NTILE reservedreserved 
NULLreservedreservedreservedreserved
NULLABLE non-reservednon-reservednon-reserved
NULLIFnon-reserved (cannot be function or type)reservedreservedreserved
NULLSnon-reservednon-reservednon-reserved 
NULL_ORDERING non-reservednon-reserved 
NUMBER non-reservednon-reservednon-reserved
NUMERICnon-reserved (cannot be function or type)reservedreservedreserved
OBJECTnon-reservednon-reservednon-reserved 
OCCURRENCE non-reservednon-reserved 
OCCURRENCES_REGEX reservedreserved 
OCTETS non-reservednon-reserved 
OCTET_LENGTH reservedreservedreserved
OFnon-reservedreservedreservedreserved
OFFnon-reservednon-reservednon-reserved 
OFFSETreserved, requires ASreservedreserved 
OIDSnon-reserved   
OLDnon-reservedreservedreserved 
OMITnon-reservedreservedreserved 
ONreserved, requires ASreservedreservedreserved
ONE reservedreserved 
ONLYreservedreservedreservedreserved
OPEN reservedreservedreserved
OPERATORnon-reserved   
OPTIONnon-reservednon-reservednon-reservedreserved
OPTIONSnon-reservednon-reservednon-reserved 
ORreservedreservedreservedreserved
ORDERreserved, requires ASreservedreservedreserved
ORDERING non-reservednon-reserved 
ORDINALITYnon-reservednon-reservednon-reserved 
OTHERSnon-reservednon-reservednon-reserved 
OUTnon-reserved (cannot be function or type)reservedreserved 
OUTERreserved (can be function or type)reservedreservedreserved
OUTPUT non-reservednon-reservedreserved
OVERnon-reserved, requires ASreservedreserved 
OVERFLOW non-reservednon-reserved 
OVERLAPSreserved (can be function or type), requires ASreservedreservedreserved
OVERLAYnon-reserved (cannot be function or type)reservedreserved 
OVERRIDINGnon-reservednon-reservednon-reserved 
OWNEDnon-reserved   
OWNERnon-reserved   
P non-reservednon-reserved 
PAD non-reservednon-reservedreserved
PARALLELnon-reserved   
PARAMETERnon-reservedreservedreserved 
PARAMETER_MODE non-reservednon-reserved 
PARAMETER_NAME non-reservednon-reserved 
PARAMETER_​ORDINAL_​POSITION non-reservednon-reserved 
PARAMETER_​SPECIFIC_​CATALOG non-reservednon-reserved 
PARAMETER_​SPECIFIC_​NAME non-reservednon-reserved 
PARAMETER_​SPECIFIC_​SCHEMA non-reservednon-reserved 
PARSERnon-reserved   
PARTIALnon-reservednon-reservednon-reservedreserved
PARTITIONnon-reservedreservedreserved 
PASCAL non-reservednon-reservednon-reserved
PASS non-reservednon-reserved 
PASSINGnon-reservednon-reservednon-reserved 
PASSTHROUGH non-reservednon-reserved 
PASSWORDnon-reserved   
PAST non-reservednon-reserved 
PATHnon-reservednon-reservednon-reserved 
PATTERN reservedreserved 
PER reservedreserved 
PERCENT reservedreserved 
PERCENTILE_CONT reservedreserved 
PERCENTILE_DISC reservedreserved 
PERCENT_RANK reservedreserved 
PERIOD reservedreserved 
PERMISSION non-reservednon-reserved 
PERMUTE non-reservednon-reserved 
PIPE non-reservednon-reserved 
PLACINGreservednon-reservednon-reserved 
PLANnon-reservednon-reservednon-reserved 
PLANSnon-reserved   
PLI non-reservednon-reservednon-reserved
POLICYnon-reserved   
PORTION reservedreserved 
POSITIONnon-reserved (cannot be function or type)reservedreservedreserved
POSITION_REGEX reservedreserved 
POWER reservedreserved 
PRECEDES reservedreserved 
PRECEDINGnon-reservednon-reservednon-reserved 
PRECISIONnon-reserved (cannot be function or type), requires ASreservedreservedreserved
PREPAREnon-reservedreservedreservedreserved
PREPAREDnon-reserved   
PRESERVEnon-reservednon-reservednon-reservedreserved
PREV non-reservednon-reserved 
PRIMARYreservedreservedreservedreserved
PRIORnon-reservednon-reservednon-reservedreserved
PRIVATE non-reservednon-reserved 
PRIVILEGESnon-reservednon-reservednon-reservedreserved
PROCEDURALnon-reserved   
PROCEDUREnon-reservedreservedreservedreserved
PROCEDURESnon-reserved   
PROGRAMnon-reserved   
PRUNE non-reservednon-reserved 
PTF reservedreserved 
PUBLIC non-reservednon-reservedreserved
PUBLICATIONnon-reserved   
QUOTEnon-reserved   
QUOTESnon-reservednon-reservednon-reserved 
RANGEnon-reservedreservedreserved 
RANK reservedreserved 
READnon-reservednon-reservednon-reservedreserved
READS reservedreserved 
REALnon-reserved (cannot be function or type)reservedreservedreserved
REASSIGNnon-reserved   
RECHECKnon-reserved   
RECOVERY non-reservednon-reserved 
RECURSIVEnon-reservedreservedreserved 
REFnon-reservedreservedreserved 
REFERENCESreservedreservedreservedreserved
REFERENCINGnon-reservedreservedreserved 
REFRESHnon-reserved   
REGR_AVGX reservedreserved 
REGR_AVGY reservedreserved 
REGR_COUNT reservedreserved 
REGR_INTERCEPT reservedreserved 
REGR_R2 reservedreserved 
REGR_SLOPE reservedreserved 
REGR_SXX reservedreserved 
REGR_SXY reservedreserved 
REGR_SYY reservedreserved 
REINDEXnon-reserved   
RELATIVEnon-reservednon-reservednon-reservedreserved
RELEASEnon-reservedreservedreserved 
RENAMEnon-reserved   
REPEATABLEnon-reservednon-reservednon-reservednon-reserved
REPLACEnon-reserved   
REPLICAnon-reserved   
REQUIRING non-reservednon-reserved 
RESETnon-reserved   
RESPECT non-reservednon-reserved 
RESTARTnon-reservednon-reservednon-reserved 
RESTORE non-reservednon-reserved 
RESTRICTnon-reservednon-reservednon-reservedreserved
RESULT reservedreserved 
RETURNnon-reservedreservedreserved 
RETURNED_CARDINALITY non-reservednon-reserved 
RETURNED_LENGTH non-reservednon-reservednon-reserved
RETURNED_​OCTET_​LENGTH non-reservednon-reservednon-reserved
RETURNED_SQLSTATE non-reservednon-reservednon-reserved
RETURNINGreserved, requires ASnon-reservednon-reserved 
RETURNSnon-reservedreservedreserved 
REVOKEnon-reservedreservedreservedreserved
RIGHTreserved (can be function or type)reservedreservedreserved
ROLEnon-reservednon-reservednon-reserved 
ROLLBACKnon-reservedreservedreservedreserved
ROLLUPnon-reservedreservedreserved 
ROUTINEnon-reservednon-reservednon-reserved 
ROUTINESnon-reserved   
ROUTINE_CATALOG non-reservednon-reserved 
ROUTINE_NAME non-reservednon-reserved 
ROUTINE_SCHEMA non-reservednon-reserved 
ROWnon-reserved (cannot be function or type)reservedreserved 
ROWSnon-reservedreservedreservedreserved
ROW_COUNT non-reservednon-reservednon-reserved
ROW_NUMBER reservedreserved 
RPAD reserved  
RTRIM reserved  
RULEnon-reserved   
RUNNING reservedreserved 
SAVEPOINTnon-reservedreservedreserved 
SCALARnon-reservednon-reservednon-reserved 
SCALE non-reservednon-reservednon-reserved
SCHEMAnon-reservednon-reservednon-reservedreserved
SCHEMASnon-reserved   
SCHEMA_NAME non-reservednon-reservednon-reserved
SCOPE reservedreserved 
SCOPE_CATALOG non-reservednon-reserved 
SCOPE_NAME non-reservednon-reserved 
SCOPE_SCHEMA non-reservednon-reserved 
SCROLLnon-reservedreservedreservedreserved
SEARCHnon-reservedreservedreserved 
SECONDnon-reserved, requires ASreservedreservedreserved
SECTION non-reservednon-reservedreserved
SECURITYnon-reservednon-reservednon-reserved 
SEEK reservedreserved 
SELECTreservedreservedreservedreserved
SELECTIVE non-reservednon-reserved 
SELF non-reservednon-reserved 
SEMANTICS non-reservednon-reserved 
SENSITIVE reservedreserved 
SEQUENCEnon-reservednon-reservednon-reserved 
SEQUENCESnon-reserved   
SERIALIZABLEnon-reservednon-reservednon-reservednon-reserved
SERVERnon-reservednon-reservednon-reserved 
SERVER_NAME non-reservednon-reservednon-reserved
SESSIONnon-reservednon-reservednon-reservedreserved
SESSION_USERreservedreservedreservedreserved
SETnon-reservedreservedreservedreserved
SETOFnon-reserved (cannot be function or type)   
SETSnon-reservednon-reservednon-reserved 
SHAREnon-reserved   
SHOWnon-reservedreservedreserved 
SIMILARreserved (can be function or type)reservedreserved 
SIMPLEnon-reservednon-reservednon-reserved 
SIN reservedreserved 
SINH reservedreserved 
SIZE non-reservednon-reservedreserved
SKIPnon-reservedreservedreserved 
SMALLINTnon-reserved (cannot be function or type)reservedreservedreserved
SNAPSHOTnon-reserved   
SOMEreservedreservedreservedreserved
SORT_DIRECTION non-reservednon-reserved 
SOURCEnon-reservednon-reservednon-reserved 
SPACE non-reservednon-reservedreserved
SPECIFIC reservedreserved 
SPECIFICTYPE reservedreserved 
SPECIFIC_NAME non-reservednon-reserved 
SQLnon-reservedreservedreservedreserved
SQLCODE   reserved
SQLERROR   reserved
SQLEXCEPTION reservedreserved 
SQLSTATE reservedreservedreserved
SQLWARNING reservedreserved 
SQRT reservedreserved 
STABLEnon-reserved   
STANDALONEnon-reservednon-reservednon-reserved 
STARTnon-reservedreservedreserved 
STATE non-reservednon-reserved 
STATEMENTnon-reservednon-reservednon-reserved 
STATIC reservedreserved 
STATISTICSnon-reserved   
STDDEV_POP reservedreserved 
STDDEV_SAMP reservedreserved 
STDINnon-reserved   
STDOUTnon-reserved   
STORAGEnon-reserved   
STOREDnon-reserved   
STRICTnon-reserved   
STRINGnon-reservednon-reservednon-reserved 
STRIPnon-reservednon-reservednon-reserved 
STRUCTURE non-reservednon-reserved 
STYLE non-reservednon-reserved 
SUBCLASS_ORIGIN non-reservednon-reservednon-reserved
SUBMULTISET reservedreserved 
SUBSCRIPTIONnon-reserved   
SUBSET reservedreserved 
SUBSTRINGnon-reserved (cannot be function or type)reservedreservedreserved
SUBSTRING_REGEX reservedreserved 
SUCCEEDS reservedreserved 
SUM reservedreservedreserved
SUPPORTnon-reserved   
SYMMETRICreservedreservedreserved 
SYSIDnon-reserved   
SYSTEMnon-reservedreservedreserved 
SYSTEM_TIME reservedreserved 
SYSTEM_USERreservedreservedreservedreserved
T non-reservednon-reserved 
TABLEreservedreservedreservedreserved
TABLESnon-reserved   
TABLESAMPLEreserved (can be function or type)reservedreserved 
TABLESPACEnon-reserved   
TABLE_NAME non-reservednon-reservednon-reserved
TAN reservedreserved 
TANH reservedreserved 
TARGETnon-reserved   
TEMPnon-reserved   
TEMPLATEnon-reserved   
TEMPORARYnon-reservednon-reservednon-reservedreserved
TEXTnon-reserved   
THENreservedreservedreservedreserved
THROUGH non-reservednon-reserved 
TIESnon-reservednon-reservednon-reserved 
TIMEnon-reserved (cannot be function or type)reservedreservedreserved
TIMESTAMPnon-reserved (cannot be function or type)reservedreservedreserved
TIMEZONE_HOUR reservedreservedreserved
TIMEZONE_MINUTE reservedreservedreserved
TOreserved, requires ASreservedreservedreserved
TOKEN non-reservednon-reserved 
TOP_LEVEL_COUNT non-reservednon-reserved 
TRAILINGreservedreservedreservedreserved
TRANSACTIONnon-reservednon-reservednon-reservedreserved
TRANSACTIONS_​COMMITTED non-reservednon-reserved 
TRANSACTIONS_​ROLLED_​BACK non-reservednon-reserved 
TRANSACTION_ACTIVE non-reservednon-reserved 
TRANSFORMnon-reservednon-reservednon-reserved 
TRANSFORMS non-reservednon-reserved 
TRANSLATE reservedreservedreserved
TRANSLATE_REGEX reservedreserved 
TRANSLATION reservedreservedreserved
TREATnon-reserved (cannot be function or type)reservedreserved 
TRIGGERnon-reservedreservedreserved 
TRIGGER_CATALOG non-reservednon-reserved 
TRIGGER_NAME non-reservednon-reserved 
TRIGGER_SCHEMA non-reservednon-reserved 
TRIMnon-reserved (cannot be function or type)reservedreservedreserved
TRIM_ARRAY reservedreserved 
TRUEreservedreservedreservedreserved
TRUNCATEnon-reservedreservedreserved 
TRUSTEDnon-reserved   
TYPEnon-reservednon-reservednon-reservednon-reserved
TYPESnon-reserved   
UESCAPEnon-reservedreservedreserved 
UNBOUNDEDnon-reservednon-reservednon-reserved 
UNCOMMITTEDnon-reservednon-reservednon-reservednon-reserved
UNCONDITIONALnon-reservednon-reservednon-reserved 
UNDER non-reservednon-reserved 
UNENCRYPTEDnon-reserved   
UNIONreserved, requires ASreservedreservedreserved
UNIQUEreservedreservedreservedreserved
UNKNOWNnon-reservedreservedreservedreserved
UNLINK non-reservednon-reserved 
UNLISTENnon-reserved   
UNLOGGEDnon-reserved   
UNMATCHED non-reservednon-reserved 
UNNAMED non-reservednon-reservednon-reserved
UNNEST reservedreserved 
UNTILnon-reserved   
UNTYPED non-reservednon-reserved 
UPDATEnon-reservedreservedreservedreserved
UPPER reservedreservedreserved
URI non-reservednon-reserved 
USAGE non-reservednon-reservedreserved
USERreservedreservedreservedreserved
USER_​DEFINED_​TYPE_​CATALOG non-reservednon-reserved 
USER_​DEFINED_​TYPE_​CODE non-reservednon-reserved 
USER_​DEFINED_​TYPE_​NAME non-reservednon-reserved 
USER_​DEFINED_​TYPE_​SCHEMA non-reservednon-reserved 
USINGreservedreservedreservedreserved
UTF16 non-reservednon-reserved 
UTF32 non-reservednon-reserved 
UTF8 non-reservednon-reserved 
VACUUMnon-reserved   
VALIDnon-reservednon-reservednon-reserved 
VALIDATEnon-reserved   
VALIDATORnon-reserved   
VALUEnon-reservedreservedreservedreserved
VALUESnon-reserved (cannot be function or type)reservedreservedreserved
VALUE_OF reservedreserved 
VARBINARY reservedreserved 
VARCHARnon-reserved (cannot be function or type)reservedreservedreserved
VARIADICreserved   
VARYINGnon-reserved, requires ASreservedreservedreserved
VAR_POP reservedreserved 
VAR_SAMP reservedreserved 
VERBOSEreserved (can be function or type)   
VERSIONnon-reservednon-reservednon-reserved 
VERSIONING reservedreserved 
VIEWnon-reservednon-reservednon-reservedreserved
VIEWSnon-reserved   
VOLATILEnon-reserved   
WHENreservedreservedreservedreserved
WHENEVER reservedreservedreserved
WHEREreserved, requires ASreservedreservedreserved
WHITESPACEnon-reservednon-reservednon-reserved 
WIDTH_BUCKET reservedreserved 
WINDOWreserved, requires ASreservedreserved 
WITHreserved, requires ASreservedreservedreserved
WITHINnon-reserved, requires ASreservedreserved 
WITHOUTnon-reserved, requires ASreservedreserved 
WORKnon-reservednon-reservednon-reservedreserved
WRAPPERnon-reservednon-reservednon-reserved 
WRITEnon-reservednon-reservednon-reservedreserved
XMLnon-reservedreservedreserved 
XMLAGG reservedreserved 
XMLATTRIBUTESnon-reserved (cannot be function or type)reservedreserved 
XMLBINARY reservedreserved 
XMLCAST reservedreserved 
XMLCOMMENT reservedreserved 
XMLCONCATnon-reserved (cannot be function or type)reservedreserved 
XMLDECLARATION non-reservednon-reserved 
XMLDOCUMENT reservedreserved 
XMLELEMENTnon-reserved (cannot be function or type)reservedreserved 
XMLEXISTSnon-reserved (cannot be function or type)reservedreserved 
XMLFORESTnon-reserved (cannot be function or type)reservedreserved 
XMLITERATE reservedreserved 
XMLNAMESPACESnon-reserved (cannot be function or type)reservedreserved 
XMLPARSEnon-reserved (cannot be function or type)reservedreserved 
XMLPInon-reserved (cannot be function or type)reservedreserved 
XMLQUERY reservedreserved 
XMLROOTnon-reserved (cannot be function or type)   
XMLSCHEMA non-reservednon-reserved 
XMLSERIALIZEnon-reserved (cannot be function or type)reservedreserved 
XMLTABLEnon-reserved (cannot be function or type)reservedreserved 
XMLTEXT reservedreserved 
XMLVALIDATE reservedreserved 
YEARnon-reserved, requires ASreservedreservedreserved
YESnon-reservednon-reservednon-reserved 
ZONEnon-reservednon-reservednon-reservedreserved

45.13. Porting from Oracle PL/SQL

This section explains differences between Postgres Pro's PL/pgSQL language and Oracle's PL/SQL language, to help developers who port applications from Oracle® to Postgres Pro.

PL/pgSQL is similar to PL/SQL in many aspects. It is a block-structured, imperative language, and all variables have to be declared. Assignments, loops, and conditionals are similar. The main differences you should keep in mind when porting from PL/SQL to PL/pgSQL are:

  • If a name used in an SQL command could be either a column name of a table used in the command or a reference to a variable of the function, PL/SQL treats it as a column name. By default, PL/pgSQL will throw an error complaining that the name is ambiguous. You can specify plpgsql.variable_conflict = use_column to change this behavior to match PL/SQL, as explained in Section 45.11.1. It's often best to avoid such ambiguities in the first place, but if you have to port a large amount of code that depends on this behavior, setting variable_conflict may be the best solution.

  • In Postgres Pro the function body must be written as a string literal. Therefore you need to use dollar quoting or escape single quotes in the function body. (See Section 45.12.1.)

  • Data type names often need translation. For example, in Oracle string values are commonly declared as being of type varchar2, which is a non-SQL-standard type. In Postgres Pro, use type varchar or text instead. Similarly, replace type number with numeric, or use some other numeric data type if there's a more appropriate one.

  • Instead of packages, use schemas to organize your functions into groups.

  • Since there are no packages, there are no package-level variables either. This is somewhat annoying. You can keep per-session state in temporary tables instead.

  • Integer FOR loops with REVERSE work differently: PL/SQL counts down from the second number to the first, while PL/pgSQL counts down from the first number to the second, requiring the loop bounds to be swapped when porting. This incompatibility is unfortunate but is unlikely to be changed. (See Section 45.6.5.5.)

  • FOR loops over queries (other than cursors) also work differently: the target variable(s) must have been declared, whereas PL/SQL always declares them implicitly. An advantage of this is that the variable values are still accessible after the loop exits.

  • There are various notational differences for the use of cursor variables.

45.13.1. Porting Examples

Example 45.9 shows how to port a simple function from PL/SQL to PL/pgSQL.

Example 45.9. Porting a Simple Function from PL/SQL to PL/pgSQL

Here is an Oracle PL/SQL function:

CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar2,
                                                  v_version varchar2)
RETURN varchar2 IS
BEGIN
    IF v_version IS NULL THEN
        RETURN v_name;
    END IF;
    RETURN v_name || '/' || v_version;
END;
/
show errors;

Let's go through this function and see the differences compared to PL/pgSQL:

  • The type name varchar2 has to be changed to varchar or text. In the examples in this section, we'll use varchar, but text is often a better choice if you do not need specific string length limits.

  • The RETURN key word in the function prototype (not the function body) becomes RETURNS in Postgres Pro. Also, IS becomes AS, and you need to add a LANGUAGE clause because PL/pgSQL is not the only possible function language.

  • In Postgres Pro, the function body is considered to be a string literal, so you need to use quote marks or dollar quotes around it. This substitutes for the terminating / in the Oracle approach.

  • The show errors command does not exist in Postgres Pro, and is not needed since errors are reported automatically.

This is how this function would look when ported to Postgres Pro:

CREATE OR REPLACE FUNCTION cs_fmt_browser_version(v_name varchar,
                                                  v_version varchar)
RETURNS varchar AS $$
BEGIN
    IF v_version IS NULL THEN
        RETURN v_name;
    END IF;
    RETURN v_name || '/' || v_version;
END;
$$ LANGUAGE plpgsql;


Example 45.10 shows how to port a function that creates another function and how to handle the ensuing quoting problems.

Example 45.10. Porting a Function that Creates Another Function from PL/SQL to PL/pgSQL

The following procedure grabs rows from a SELECT statement and builds a large function with the results in IF statements, for the sake of efficiency.

This is the Oracle version:

CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc IS
    CURSOR referrer_keys IS
        SELECT * FROM cs_referrer_keys
        ORDER BY try_order;
    func_cmd VARCHAR(4000);
BEGIN
    func_cmd := 'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host IN VARCHAR2,
                 v_domain IN VARCHAR2, v_url IN VARCHAR2) RETURN VARCHAR2 IS BEGIN';

    FOR referrer_key IN referrer_keys LOOP
        func_cmd := func_cmd ||
          ' IF v_' || referrer_key.kind
          || ' LIKE ''' || referrer_key.key_string
          || ''' THEN RETURN ''' || referrer_key.referrer_type
          || '''; END IF;';
    END LOOP;

    func_cmd := func_cmd || ' RETURN NULL; END;';

    EXECUTE IMMEDIATE func_cmd;
END;
/
show errors;

Here is how this function would end up in Postgres Pro:

CREATE OR REPLACE PROCEDURE cs_update_referrer_type_proc() AS $func$
DECLARE
    referrer_keys CURSOR IS
        SELECT * FROM cs_referrer_keys
        ORDER BY try_order;
    func_body text;
    func_cmd text;
BEGIN
    func_body := 'BEGIN';

    FOR referrer_key IN referrer_keys LOOP
        func_body := func_body ||
          ' IF v_' || referrer_key.kind
          || ' LIKE ' || quote_literal(referrer_key.key_string)
          || ' THEN RETURN ' || quote_literal(referrer_key.referrer_type)
          || '; END IF;' ;
    END LOOP;

    func_body := func_body || ' RETURN NULL; END;';

    func_cmd :=
      'CREATE OR REPLACE FUNCTION cs_find_referrer_type(v_host varchar,
                                                        v_domain varchar,
                                                        v_url varchar)
        RETURNS varchar AS '
      || quote_literal(func_body)
      || ' LANGUAGE plpgsql;' ;

    EXECUTE func_cmd;
END;
$func$ LANGUAGE plpgsql;

Notice how the body of the function is built separately and passed through quote_literal to double any quote marks in it. This technique is needed because we cannot safely use dollar quoting for defining the new function: we do not know for sure what strings will be interpolated from the referrer_key.key_string field. (We are assuming here that referrer_key.kind can be trusted to always be host, domain, or url, but referrer_key.key_string might be anything, in particular it might contain dollar signs.) This function is actually an improvement on the Oracle original, because it will not generate broken code when referrer_key.key_string or referrer_key.referrer_type contain quote marks.


Example 45.11 shows how to port a function with OUT parameters and string manipulation. Postgres Pro does not have a built-in instr function, but you can create one using a combination of other functions. In Section 45.13.3 there is a PL/pgSQL implementation of instr that you can use to make your porting easier.

Example 45.11. Porting a Procedure With String Manipulation and OUT Parameters from PL/SQL to PL/pgSQL

The following Oracle PL/SQL procedure is used to parse a URL and return several elements (host, path, and query).

This is the Oracle version:

CREATE OR REPLACE PROCEDURE cs_parse_url(
    v_url IN VARCHAR2,
    v_host OUT VARCHAR2,  -- This will be passed back
    v_path OUT VARCHAR2,  -- This one too
    v_query OUT VARCHAR2) -- And this one
IS
    a_pos1 INTEGER;
    a_pos2 INTEGER;
BEGIN
    v_host := NULL;
    v_path := NULL;
    v_query := NULL;
    a_pos1 := instr(v_url, '//');

    IF a_pos1 = 0 THEN
        RETURN;
    END IF;
    a_pos2 := instr(v_url, '/', a_pos1 + 2);
    IF a_pos2 = 0 THEN
        v_host := substr(v_url, a_pos1 + 2);
        v_path := '/';
        RETURN;
    END IF;

    v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
    a_pos1 := instr(v_url, '?', a_pos2 + 1);

    IF a_pos1 = 0 THEN
        v_path := substr(v_url, a_pos2);
        RETURN;
    END IF;

    v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
    v_query := substr(v_url, a_pos1 + 1);
END;
/
show errors;

Here is a possible translation into PL/pgSQL:

CREATE OR REPLACE FUNCTION cs_parse_url(
    v_url IN VARCHAR,
    v_host OUT VARCHAR,  -- This will be passed back
    v_path OUT VARCHAR,  -- This one too
    v_query OUT VARCHAR) -- And this one
AS $$
DECLARE
    a_pos1 INTEGER;
    a_pos2 INTEGER;
BEGIN
    v_host := NULL;
    v_path := NULL;
    v_query := NULL;
    a_pos1 := instr(v_url, '//');

    IF a_pos1 = 0 THEN
        RETURN;
    END IF;
    a_pos2 := instr(v_url, '/', a_pos1 + 2);
    IF a_pos2 = 0 THEN
        v_host := substr(v_url, a_pos1 + 2);
        v_path := '/';
        RETURN;
    END IF;

    v_host := substr(v_url, a_pos1 + 2, a_pos2 - a_pos1 - 2);
    a_pos1 := instr(v_url, '?', a_pos2 + 1);

    IF a_pos1 = 0 THEN
        v_path := substr(v_url, a_pos2);
        RETURN;
    END IF;

    v_path := substr(v_url, a_pos2, a_pos1 - a_pos2);
    v_query := substr(v_url, a_pos1 + 1);
END;
$$ LANGUAGE plpgsql;

This function could be used like this:

SELECT * FROM cs_parse_url('http://foobar.com/query.cgi?baz');


Example 45.12 shows how to port a procedure that uses numerous features that are specific to Oracle.

Example 45.12. Porting a Procedure from PL/SQL to PL/pgSQL

The Oracle version:

CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id IN INTEGER) IS
    a_running_job_count INTEGER;
BEGIN
    LOCK TABLE cs_jobs IN EXCLUSIVE MODE;

    SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;

    IF a_running_job_count > 0 THEN
        COMMIT; -- free lock
        raise_application_error(-20000,
                 'Unable to create a new job: a job is currently running.');
    END IF;

    DELETE FROM cs_active_job;
    INSERT INTO cs_active_job(job_id) VALUES (v_job_id);

    BEGIN
        INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, now());
    EXCEPTION
        WHEN dup_val_on_index THEN NULL; -- don't worry if it already exists
    END;
    COMMIT;
END;
/
show errors

This is how we could port this procedure to PL/pgSQL:

CREATE OR REPLACE PROCEDURE cs_create_job(v_job_id integer) AS $$
DECLARE
    a_running_job_count integer;
BEGIN
    LOCK TABLE cs_jobs IN EXCLUSIVE MODE;

    SELECT count(*) INTO a_running_job_count FROM cs_jobs WHERE end_stamp IS NULL;

    IF a_running_job_count > 0 THEN
        COMMIT; -- free lock
        RAISE EXCEPTION 'Unable to create a new job: a job is currently running'; -- (1)
    END IF;

    DELETE FROM cs_active_job;
    INSERT INTO cs_active_job(job_id) VALUES (v_job_id);

    BEGIN
        INSERT INTO cs_jobs (job_id, start_stamp) VALUES (v_job_id, now());
    EXCEPTION
        WHEN unique_violation THEN -- (2)
            -- don't worry if it already exists
    END;
    COMMIT;
END;
$$ LANGUAGE plpgsql;

(1)

The syntax of RAISE is considerably different from Oracle's statement, although the basic case RAISE exception_name works similarly.

(2)

The exception names supported by PL/pgSQL are different from Oracle's. The set of built-in exception names is much larger (see Appendix A). There is not currently a way to declare user-defined exception names, although you can throw user-chosen SQLSTATE values instead.


45.13.2. Other Things to Watch For

This section explains a few other things to watch for when porting Oracle PL/SQL functions to Postgres Pro.

45.13.2.1. Implicit Rollback after Exceptions

In PL/pgSQL, when an exception is caught by an EXCEPTION clause, all database changes since the block's BEGIN are automatically rolled back. That is, the behavior is equivalent to what you'd get in Oracle with:

BEGIN
    SAVEPOINT s1;
    ... code here ...
EXCEPTION
    WHEN ... THEN
        ROLLBACK TO s1;
        ... code here ...
    WHEN ... THEN
        ROLLBACK TO s1;
        ... code here ...
END;

If you are translating an Oracle procedure that uses SAVEPOINT and ROLLBACK TO in this style, your task is easy: just omit the SAVEPOINT and ROLLBACK TO. If you have a procedure that uses SAVEPOINT and ROLLBACK TO in a different way then some actual thought will be required.

45.13.2.2. EXECUTE

The PL/pgSQL version of EXECUTE works similarly to the PL/SQL version, but you have to remember to use quote_literal and quote_ident as described in Section 45.5.4. Constructs of the type EXECUTE 'SELECT * FROM $1'; will not work reliably unless you use these functions.

45.13.2.3. Optimizing PL/pgSQL Functions

Postgres Pro gives you two function creation modifiers to optimize execution: volatility (whether the function always returns the same result when given the same arguments) and strictness (whether the function returns null if any argument is null). Consult the CREATE FUNCTION reference page for details.

When making use of these optimization attributes, your CREATE FUNCTION statement might look something like this:

CREATE FUNCTION foo(...) RETURNS integer AS $$
...
$$ LANGUAGE plpgsql STRICT IMMUTABLE;

45.13.3. Appendix

This section contains the code for a set of Oracle-compatible instr functions that you can use to simplify your porting efforts.

--
-- instr functions that mimic Oracle's counterpart
-- Syntax: instr(string1, string2 [, n [, m]])
-- where [] denotes optional parameters.
--
-- Search string1, beginning at the nth character, for the mth occurrence
-- of string2.  If n is negative, search backwards, starting at the abs(n)'th
-- character from the end of string1.
-- If n is not passed, assume 1 (search starts at first character).
-- If m is not passed, assume 1 (find first occurrence).
-- Returns starting index of string2 in string1, or 0 if string2 is not found.
--

CREATE FUNCTION instr(varchar, varchar) RETURNS integer AS $$
BEGIN
    RETURN instr($1, $2, 1);
END;
$$ LANGUAGE plpgsql STRICT IMMUTABLE;


CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
                      beg_index integer)
RETURNS integer AS $$
DECLARE
    pos integer NOT NULL DEFAULT 0;
    temp_str varchar;
    beg integer;
    length integer;
    ss_length integer;
BEGIN
    IF beg_index > 0 THEN
        temp_str := substring(string FROM beg_index);
        pos := position(string_to_search_for IN temp_str);

        IF pos = 0 THEN
            RETURN 0;
        ELSE
            RETURN pos + beg_index - 1;
        END IF;
    ELSIF beg_index < 0 THEN
        ss_length := char_length(string_to_search_for);
        length := char_length(string);
        beg := length + 1 + beg_index;

        WHILE beg > 0 LOOP
            temp_str := substring(string FROM beg FOR ss_length);
            IF string_to_search_for = temp_str THEN
                RETURN beg;
            END IF;

            beg := beg - 1;
        END LOOP;

        RETURN 0;
    ELSE
        RETURN 0;
    END IF;
END;
$$ LANGUAGE plpgsql STRICT IMMUTABLE;


CREATE FUNCTION instr(string varchar, string_to_search_for varchar,
                      beg_index integer, occur_index integer)
RETURNS integer AS $$
DECLARE
    pos integer NOT NULL DEFAULT 0;
    occur_number integer NOT NULL DEFAULT 0;
    temp_str varchar;
    beg integer;
    i integer;
    length integer;
    ss_length integer;
BEGIN
    IF occur_index <= 0 THEN
        RAISE 'argument ''%'' is out of range', occur_index
          USING ERRCODE = '22003';
    END IF;

    IF beg_index > 0 THEN
        beg := beg_index - 1;
        FOR i IN 1..occur_index LOOP
            temp_str := substring(string FROM beg + 1);
            pos := position(string_to_search_for IN temp_str);
            IF pos = 0 THEN
                RETURN 0;
            END IF;
            beg := beg + pos;
        END LOOP;

        RETURN beg;
    ELSIF beg_index < 0 THEN
        ss_length := char_length(string_to_search_for);
        length := char_length(string);
        beg := length + 1 + beg_index;

        WHILE beg > 0 LOOP
            temp_str := substring(string FROM beg FOR ss_length);
            IF string_to_search_for = temp_str THEN
                occur_number := occur_number + 1;
                IF occur_number = occur_index THEN
                    RETURN beg;
                END IF;
            END IF;

            beg := beg - 1;
        END LOOP;

        RETURN 0;
    ELSE
        RETURN 0;
    END IF;
END;
$$ LANGUAGE plpgsql STRICT IMMUTABLE;