C language to achieve the conversion function of the example

  • 2020-05-27 06:46:17
  • OfStack

C language to achieve the conversion function of the example

Preface:

Write 1 base 2, 8, 106 to 10

Requirements:

The function takes two parameters, parameter (1) is the number to be converted to hexadecimal, and parameter (2) is the number to be converted to hexadecimal (2,8,16). If you have an error message, for example, parameter 1012, but parameter (2) is 2, it's obviously a base number that means there's an error.

The system table pg_proc stores information about functions

Internal function need to define first before compilation in pg_proc. h, src include/catalog/pg_proc h


CATALOG(pg_proc,1255) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81) BKI_SCHEMA_MACRO
{
 NameData proname; /* procedure name */ /*  The function name, sql  In the  select  The function name (); */
 Oid  pronamespace; /* OID of namespace containing this proc */  /*  model OID */
 Oid  proowner; /* procedure owner */ /*  The user OID */
 Oid  prolang; /* OID of pg_language entry */
 float4 procost; /* estimated execution cost */  /*  Estimated execution cost  */
 float4 prorows; /* estimated # of rows out (if proretset) */ /*  Result row estimates  */
 Oid  provariadic; /* element type of variadic array, or 0 */
 regproc protransform; /* transforms calls to it during planning */
 bool proisagg; /* is it an aggregate? */ /*  Is it an aggregate function  */
 bool proiswindow; /* is it a window function? */  /*  Is a window function  */
 bool prosecdef; /* security definer */  /*  The function is 1 Security definer, which is 1 A" setuid" function  */
 bool proleakproof; /* is it a leak-proof function? */  /*  Whether there are other effects  */
 bool proisstrict; /* strict with respect to NULLs? */ /*  encounter  NULL  Whether the value is returned directly  NULL */
 bool proretset; /* returns a set? */ /*  The function returns 1 A collection of  */
 char provolatile; /* see PROVOLATILE_ categories below */
 int16 pronargs; /* number of arguments */ /*  Number of parameters  */
 int16 pronargdefaults; /* number of arguments with defaults */ /*  Number of default parameters  */
 Oid  prorettype; /* OID of result type */ /*  Return parameter type OID */

 /*
 * variable-length fields start here, but we allow direct access to
 * proargtypes
 */
 oidvector proargtypes; /* parameter types (excludes OUT params) */ /*  An array of function parameter types  */

#ifdef CATALOG_VARLEN
 Oid  proallargtypes[1]; /* all param types (NULL if IN only) */
 char proargmodes[1]; /* parameter modes (NULL if IN only) */
 text proargnames[1]; /* parameter names (NULL if no names) */
 pg_node_tree proargdefaults;/* list of expression trees for argument
     * defaults (NULL if none) */
 Oid  protrftypes[1]; /* types for which to apply transforms */
 text prosrc BKI_FORCE_NOT_NULL; /* procedure source text */ /*  How does a function processor call a function and implement the name of the function  */
 text probin;  /* secondary procedure info (can be NULL) */
 text proconfig[1]; /* procedure-local GUC settings */
 aclitem proacl[1]; /* access permissions */
#endif
} FormData_pg_proc;

Add the function definition in proc.h:


/* myfunc */
DATA(insert OID = 6663 ( x_to_dec PGNSP PGUID 12 1 0 0 0 f f f f t f i 2 0 23 "25 23" _null_ _null_ _null_ _null_ _null_ x_to_dec _null_ _null_ _null_ ));
DESCR("x_to_dec.");

OID = 6663  /* OID  only 1 Cannot be defined with other definitions  OID  repeat  */
x_to_dec  /* sql  In the  select x_to_dec(); */
2 0 23 "25 23"  /*  Pass two parameters ;  The default  0;  Return value type  OID = 23;  parameter 1 type  OID = 25,  parameter 2 type  OID = 23 */
x_to_dec  /*  Custom function names  */

OID is used for both the pass-through parameter type and the return value type

The system table pg_type stores information about the data type


postgres=# select oid,typname from pg_type where typname = 'text' or typname = 'int4';
 oid | typname 
-----+---------
 23 | int4
 25 | text
(2 rows)

In src/backend/utils/adt/myfuncs c implement custom function

First create the whole part of the function:


Datum  /* Datum  Type is PG The system function refers to a large number of types, which are defined as: typedef uintptr_c Datum */
x_to_dec (PG_FUNCTION_ARGS)  /*  The function name ;  parameter  */
{
  /*  To obtain parameters  */
 text *arg1 = PG_GETARG_TEXT_P(0);
 int32 arg2 = PG_GETARG_INT32(1);

  /**  Realize the function  **/

  /*  return  */
 PG_RETURN_INT32(sum);
}

PG_GETARG_XXXX here () and PG_RETURN_XXXXX () in the src/include/fmgr h

Now that you know how to get the parameters and return the return value, here's the implementation:


Datum x_to_dec (PG_FUNCTION_ARGS)
{
 int n = 0, i = 0, sum = 0, t = 0;
 text *arg1 = PG_GETARG_TEXT_P(0);
 int32 arg2 = PG_GETARG_INT32(1);
 char *str = text_to_cstring(arg1);
 n = strlen(str);

 switch(arg2)
 {
 case 2:
  for(i = n - 1; i >= 0; i--)
  {
  if((str[i] - '0') != 1 && (str[i] - '0') != 0)
  {
   ereport(ERROR,
   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
   errmsg("Please enter the correct binary number, such as '110011'.")));
  }
  sum += (str[i] - '0') * ((int)pow(2, n - 1 - i));
  }
  break;
 case 8:
  for(i = n - 1; i >= 0; i--)
  {
  if(!(str[i] >= '0' && str[i] <= '7'))
  {
   ereport(ERROR,
   (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
   errmsg("Please enter the correct octal number, for example '34567'.")));
  }
  sum += (str[i] - '0') * ((int)pow(8, n - 1 - i));
  }
  break;
 case 16:
  for(i = n - 1; i >= 0; i--)
  {
  if( !(str[i] >= '0' && str[i] <= '9') )
  {
   if(str[i] >= 'A' && str[i] <= 'F')
   {
   // Uppercase to lowercase
   str[i] = str[i] + 32;
   } else if ( !(str[i] >= 'a' && str[i] <= 'f') ) {
   ereport(ERROR,
    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
    errmsg("Please enter the correct hexadecimal number, for example '9f'.")));
   }
  }
  if(str[i] <= '9')
  {
   t = str[i] - '0';
  } else {
   t = str[i] - 'a' + 10;
  }
  sum = sum * 16 + t;
  }
  break;
 default:
  ereport(ERROR,
  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
  errmsg("Out of range! The second parameter, please enter: 2, 4, 16.")));
 }

 PG_RETURN_INT32(sum);
}

Which USES text_to_cstring (arg1), type conversion of related functions defined in src/backend/utils/adt/varlena c


/*
 * text_to_cstring
 *
 * Create a palloc'd, null-terminated C string from a text value.
 *
 * We support being passed a compressed or toasted text value.
 * This is a bit bogus since such values shouldn't really be referred to as
 * "text *", but it seems useful for robustness. If we didn't handle that
 * case here, we'd need another routine that did, anyway.
 */
char *
text_to_cstring(const text *t)
{
 /* must cast away the const, unfortunately */
 text  *tunpacked = pg_detoast_datum_packed((struct varlena *) t);
 int  len = VARSIZE_ANY_EXHDR(tunpacked);
 char  *result;

 result = (char *) palloc(len + 1);
 memcpy(result, VARDATA_ANY(tunpacked), len);
 result[len] = '\0';

 if (tunpacked != t)
 pfree(tunpacked);

 return result;
}

Results:


postgres=# select x_to_dec('111',2);
 x_to_dec 
----------
    7
(1 row)

postgres=# select x_to_dec('aA',16);
 x_to_dec 
----------
   170
(1 row)

postgres=# select x_to_dec('aA',1);
ERROR: Out of range! The second parameter, please enter: 2, 4, 16.
 

Above is the base conversion of the example, if you have questions please leave a message or to the site community exchange discussion, thank you for reading, hope to help you, thank you for the support of the site!


Related articles: