Last active
August 7, 2020 17:19
-
-
Save tallpeak/da9b309a2d87c64320d33b7b4011f1b2 to your computer and use it in GitHub Desktop.
UPC checkdigit calculation as a Postgresql C extension function
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
~/src/postgresql-12.2/src/tutorial# cat upc_checksum.c | |
#include "postgres.h" | |
#include <string.h> | |
#include "fmgr.h" | |
#include "utils/geo_decls.h" | |
PG_MODULE_MAGIC; | |
/* by value */ | |
PG_FUNCTION_INFO_V1(upc_checksum); | |
Datum | |
upc_checksum(PG_FUNCTION_ARGS) | |
{ | |
text *upc = PG_GETARG_TEXT_PP(0); | |
int sum = 0; | |
int mult = 3; | |
char *pstart = VARDATA_ANY(upc); | |
char *p = pstart + VARSIZE_ANY_EXHDR(upc); | |
while (--p >= pstart) { | |
unsigned int digit = *p - '0'; | |
if (digit < 10) { | |
sum += digit * mult; | |
mult ^= 2; | |
} | |
} | |
sum = (500 - sum) % 10; | |
// sum = ( 10 - ( sum % 10 ) ) % 10; | |
PG_RETURN_INT32(sum); | |
} | |
Putting the function into a path that is accessible (I know /tmp is a bad choice, but it worked) | |
% cat upc_checksum.sh | |
cc -fPIC -c upc_checksum.c -I/usr/local/pgsql/include/server/ | |
cc -shared -o upc_checksum.so upc_checksum.o | |
cp upc_checksum.* /tmp/ | |
Installing the function: | |
% psql postgres | |
[local] root@streetpulse=# drop FUNCTION upc_checksum; | |
DROP FUNCTION | |
Time: 4.181 ms | |
[local] root@streetpulse=# CREATE FUNCTION upc_checksum(text) RETURNS integer | |
AS '/tmp/upc_checksum.so', 'upc_checksum' | |
LANGUAGE C STRICT; | |
CREATE FUNCTION | |
Time: 5.101 ms | |
[local] root@streetpulse=# DO $proc$ | |
DECLARE | |
StartTime timestamptz; | |
EndTime timestamptz; | |
Delta double precision; | |
rc int; | |
BEGIN | |
StartTime := clock_timestamp(); | |
SELECT count(*) into rc | |
from tbl_superfile | |
where right(upc14,1)<>upc_checksum(upc_number||'')::text; | |
EndTime := clock_timestamp(); | |
Delta := ( extract(epoch from EndTime) - extract(epoch from StartTime) ); | |
RAISE NOTICE 'Duration in secs=%, rc=%', Delta, rc; | |
END; | |
$proc$; | |
NOTICE: 00000: Duration in secs=3.3357880115509033, rc=6037 | |
LOCATION: exec_stmt_raise, pl_exec.c:3827 | |
DO | |
Time: 3339.333 ms (00:03.339) | |
Ref: https://www.postgresql.org/docs/13/xfunc-c.html#XFUNC-C-DYNLOAD |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment