Compare commits
10 Commits
b6884d6398
...
1df8abb7d2
Author | SHA1 | Date |
---|---|---|
jordi fita mas | 1df8abb7d2 | |
Yorick de Wid | 0e533afb4d | |
Yorick de Wid | c93ff49861 | |
Yorick de Wid | 42fe111b70 | |
Yorick de Wid | 2bc89b66e8 | |
Yorick de Wid | e935980bad | |
Yorick de Wid | 33b40f623c | |
Yorick de Wid | 7a8dc557b7 | |
Yorick de Wid | 38fe81f14e | |
Yorick de Wid | c3511292b0 |
|
@ -15,11 +15,7 @@ jobs:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Install PostgreSQL development tools
|
- name: Install PostgreSQL development tools
|
||||||
run: sudo apt install postgresql-server-dev-13
|
run: sudo apt install postgresql-server-dev-13
|
||||||
# - name: configure
|
- name: Make
|
||||||
# run: ./configure
|
|
||||||
- name: make
|
|
||||||
run: make
|
run: make
|
||||||
# - name: make check
|
# - name: Install
|
||||||
# run: make check
|
# run: sudo make install
|
||||||
# - name: make distcheck
|
|
||||||
# run: make distcheck
|
|
||||||
|
|
43
README.md
43
README.md
|
@ -1,23 +1,34 @@
|
||||||
# PostgreSQL-IBAN
|
![C/C++ CI](https://github.com/yorickdewid/PostgreSQL-IBAN/workflows/C/C++%20CI/badge.svg)
|
||||||
|
|
||||||
|
# PostgreSQL IBAN
|
||||||
PostgreSQL IBAN extension that can verify International Bank Account Numbers.
|
PostgreSQL IBAN extension that can verify International Bank Account Numbers.
|
||||||
This ensures that only valid bank account numbers are stored.
|
This ensures that only valid bank account numbers are stored.
|
||||||
|
|
||||||
### Example
|
### Example
|
||||||
```sql
|
```sql
|
||||||
CREATE TABLE test_iban (
|
CREATE TABLE test_iban (
|
||||||
id serial NOT NULL,
|
name text,
|
||||||
name character varying(32),
|
account iban
|
||||||
account iban,
|
|
||||||
CONSTRAINT test_iban_pkey PRIMARY KEY (id)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
--
|
||||||
-- Insert data
|
-- Insert data
|
||||||
INSERT INTO test_iban (name, account) VALUES ('John', 'NL91ABNA0417164300'); -- Dutch IBAN format
|
--
|
||||||
INSERT INTO test_iban (name, account) VALUES ('Doe', 'DE89370400440532013000'); -- German IBAN format
|
|
||||||
|
|
||||||
-- Invalid bank account
|
-- Dutch IBAN format
|
||||||
|
INSERT INTO test_iban (name, account) VALUES ('John', 'NL91ABNA0417164300');
|
||||||
|
-- German IBAN format
|
||||||
|
INSERT INTO test_iban (name, account) VALUES ('Doe', 'DE89370400440532013000');
|
||||||
|
|
||||||
|
-- Invalid data
|
||||||
INSERT INTO test_iban (name, account) VALUES ('Dean', 'AZ22NABZ00000000137010001944');
|
INSERT INTO test_iban (name, account) VALUES ('Dean', 'AZ22NABZ00000000137010001944');
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Show output
|
||||||
|
--
|
||||||
|
|
||||||
|
SELECT * FROM test_iban;
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Manually test input
|
Manually test input
|
||||||
|
@ -31,3 +42,19 @@ the `::iban` datatype can be cast to an text to perform string operations
|
||||||
```sql
|
```sql
|
||||||
SELECT 'KZ86125KZT5004100100'::iban::text;
|
SELECT 'KZ86125KZT5004100100'::iban::text;
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
Make sure PostgreSQL development tools are installed (check `pg_config`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/yorickdewid/PostgreSQL-IBAN
|
||||||
|
cd PostgreSQL-IBAN
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Login to the database and load the extension
|
||||||
|
|
||||||
|
```sql
|
||||||
|
CREATE EXTENSION iban;
|
||||||
|
```
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
postgresql-iban (1.0.0~git15.g0e533af-1) bookworm; urgency=medium
|
||||||
|
|
||||||
|
* Add Debian packaging
|
||||||
|
|
||||||
|
-- jordi fita mas <jordi@tandem.blog> Mon, 19 Jun 2023 08:54:47 +0000
|
|
@ -0,0 +1,22 @@
|
||||||
|
Source: postgresql-iban
|
||||||
|
Section: database
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: jordi fita mas <jordi@tandem.blog>
|
||||||
|
Build-Depends:
|
||||||
|
debhelper-compat (= 13),
|
||||||
|
postgresql-all (>= 217~),
|
||||||
|
Standards-Version: 4.6.0
|
||||||
|
Vcs-Browser: https://github.com/yorickdewid/PostgreSQL-IBAN
|
||||||
|
Vcs-Git: https://github.com/yorickdewid/PostgreSQL-IBAN.git
|
||||||
|
Homepage: https://github.com/yorickdewid/PostgreSQL-IBAN
|
||||||
|
Rules-Requires-Root: no
|
||||||
|
|
||||||
|
Package: postgresql-15-iban
|
||||||
|
Architecture: any
|
||||||
|
Depends:
|
||||||
|
${shlibs:Depends},
|
||||||
|
${misc:Depends},
|
||||||
|
${postgresql:Depends}
|
||||||
|
description: IBAN type for PostgreSQL
|
||||||
|
PostgreSQL IBAN extension that can verify International Bank Account Numbers.
|
||||||
|
This ensures that only valid bank account numbers are stored.
|
|
@ -0,0 +1,22 @@
|
||||||
|
Source: postgresql-iban
|
||||||
|
Section: database
|
||||||
|
Priority: optional
|
||||||
|
Maintainer: jordi fita mas <jordi@tandem.blog>
|
||||||
|
Build-Depends:
|
||||||
|
debhelper-compat (= 13),
|
||||||
|
postgresql-all (>= 217~),
|
||||||
|
Standards-Version: 4.6.0
|
||||||
|
Vcs-Browser: https://github.com/yorickdewid/PostgreSQL-IBAN
|
||||||
|
Vcs-Git: https://github.com/yorickdewid/PostgreSQL-IBAN.git
|
||||||
|
Homepage: https://github.com/yorickdewid/PostgreSQL-IBAN
|
||||||
|
Rules-Requires-Root: no
|
||||||
|
|
||||||
|
Package: postgresql-PGVERSION-iban
|
||||||
|
Architecture: any
|
||||||
|
Depends:
|
||||||
|
${shlibs:Depends},
|
||||||
|
${misc:Depends},
|
||||||
|
${postgresql:Depends}
|
||||||
|
description: IBAN type for PostgreSQL
|
||||||
|
PostgreSQL IBAN extension that can verify International Bank Account Numbers.
|
||||||
|
This ensures that only valid bank account numbers are stored.
|
|
@ -0,0 +1,29 @@
|
||||||
|
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||||
|
Source: https://github.com/yorickdewid/PostgreSQL-IBAN
|
||||||
|
Upstream-Name: PostgreSQL-IBAN
|
||||||
|
Upstream-Contact: yorick17@outlook.com
|
||||||
|
|
||||||
|
Files: *
|
||||||
|
Copyright: 2016 Yorick de Wid
|
||||||
|
License: GPL-3+
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
Comment:
|
||||||
|
On Debian systems, the complete text of the GNU General Public
|
||||||
|
License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
||||||
|
|
||||||
|
Files: debian/*
|
||||||
|
Copyright: 2023 jordi fita mas
|
||||||
|
License: GPL-3+
|
||||||
|
This debian package is distributed under the same license as the source
|
||||||
|
package.
|
|
@ -0,0 +1 @@
|
||||||
|
13+
|
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
include /usr/share/postgresql-common/pgxs_debian_control.mk
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --with pgxs_loop
|
|
@ -0,0 +1 @@
|
||||||
|
3.0 (quilt)
|
717
iban.cpp
717
iban.cpp
|
@ -1,6 +1,7 @@
|
||||||
/*
|
/*
|
||||||
* IBAN: PostgreSQL functions and datatype
|
* IBAN: PostgreSQL functions and datatype
|
||||||
* Copyright © 2016 Yorick de Wid <yorick17@outlook.com>
|
* Copyright © 2016 Yorick de Wid <yorick17@outlook.com>
|
||||||
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
@ -21,32 +22,49 @@ extern "C"
|
||||||
{
|
{
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
|
||||||
#include <cctype>
|
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
|
||||||
#include "specification.h"
|
class Specification {
|
||||||
#include "validate.h"
|
public:
|
||||||
|
Specification(std::string structure, size_t length)
|
||||||
|
: structure{ structure }
|
||||||
|
, m_length{ length }
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
// #define PG_RETURN_IBAN_P(x) PG_RETURN_POINTER(x)
|
inline size_t getLength() const noexcept
|
||||||
|
{
|
||||||
|
return m_length;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
std::string structure;
|
||||||
{
|
|
||||||
PG_MODULE_MAGIC;
|
|
||||||
|
|
||||||
typedef char Iban;
|
private:
|
||||||
}
|
size_t m_length;
|
||||||
|
};
|
||||||
|
|
||||||
void Validate::addSpecification(Specification* specPtr) {
|
class Validate {
|
||||||
this->specifications[specPtr->countryCode] = specPtr;
|
public:
|
||||||
}
|
Validate();
|
||||||
|
|
||||||
|
bool isValid(std::string arg);
|
||||||
|
|
||||||
|
void addSpecification(std::string countryCode, size_t length, std::string structure) noexcept
|
||||||
|
{
|
||||||
|
specifications.emplace(countryCode, std::make_unique<Specification>(structure, length));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, std::unique_ptr<Specification>> specifications;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Validator global instance. */
|
||||||
|
static Validate validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates the MOD 97 10 of the passed IBAN as specified in ISO7064.
|
* Calculates the MOD 97 10 of the passed IBAN as specified in ISO7064.
|
||||||
|
@ -54,37 +72,48 @@ void Validate::addSpecification(Specification* specPtr) {
|
||||||
* @param string iban
|
* @param string iban
|
||||||
* @returns {bool}
|
* @returns {bool}
|
||||||
*/
|
*/
|
||||||
bool iso7064Mod97_10(std::string iBan) {
|
static bool iso7064Mod97_10(std::string iban) {
|
||||||
std::rotate(iBan.begin(), iBan.begin() + 4, iBan.end());
|
std::rotate(iban.begin(), iban.begin() + 4, iban.end());
|
||||||
std::string numberstring;//will contain the letter substitutions
|
|
||||||
for (const auto& c : iBan) {
|
/* Will contain the letter substitutions */
|
||||||
if (std::isdigit(c))
|
std::string numberstring;
|
||||||
|
numberstring.reserve(iban.size());
|
||||||
|
|
||||||
|
for (const auto& c : iban) {
|
||||||
|
if (std::isdigit(c)) {
|
||||||
numberstring += c;
|
numberstring += c;
|
||||||
if (std::isupper(c))
|
}
|
||||||
|
if (std::isupper(c)) {
|
||||||
numberstring += std::to_string(static_cast<int>(c) - 55);
|
numberstring += std::to_string(static_cast<int>(c) - 55);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//implements a stepwise check for mod 97 in chunks of 9 at the first time
|
|
||||||
// , then in chunks of seven prepended by the last mod 97 operation converted
|
/*
|
||||||
//to a string
|
* Implements a stepwise check for mod 97 in chunks of 9 at the first time
|
||||||
int segstart = 0;
|
* then in chunks of seven prepended by the last mod 97 operation converted
|
||||||
|
* to a string
|
||||||
|
*/
|
||||||
|
size_t segstart = 0;
|
||||||
int step = 9;
|
int step = 9;
|
||||||
std::string prepended;
|
std::string prepended;
|
||||||
long number = 0;
|
long number = 0;
|
||||||
while (segstart < numberstring.length() - step) {
|
while (segstart < numberstring.length() - step) {
|
||||||
number = std::stol(prepended + numberstring.substr(segstart, step));
|
number = std::stol(prepended + numberstring.substr(segstart, step));
|
||||||
int remainder = number % 97;
|
int remainder = number % 97;
|
||||||
prepended = std::to_string(remainder);
|
prepended = std::to_string(remainder);
|
||||||
if (remainder < 10)
|
if (remainder < 10) {
|
||||||
prepended = "0" + prepended;
|
prepended = "0" + prepended;
|
||||||
|
}
|
||||||
segstart = segstart + step;
|
segstart = segstart + step;
|
||||||
step = 7;
|
step = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
number = std::stol(prepended + numberstring.substr(segstart));
|
number = std::stol(prepended + numberstring.substr(segstart));
|
||||||
return (number % 97 == 1);
|
return number % 97 == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* parse the bban structure used to configure each iban specification and returns a matching regular expression.
|
* Parse the IBAN structure used to configure each iban specification and returns a matching regular expression.
|
||||||
* a structure is composed of blocks of 3 characters (one letter and 2 digits). each block represents
|
* a structure is composed of blocks of 3 characters (one letter and 2 digits). each block represents
|
||||||
* a logical group in the typical representation of the bban. for each group, the letter indicates which characters
|
* a logical group in the typical representation of the bban. for each group, the letter indicates which characters
|
||||||
* are allowed in this group and the following 2-digits number tells the length of the group.
|
* are allowed in this group and the following 2-digits number tells the length of the group.
|
||||||
|
@ -92,14 +121,13 @@ bool iso7064Mod97_10(std::string iBan) {
|
||||||
* @param {string} structure the structure to parse
|
* @param {string} structure the structure to parse
|
||||||
* @returns {regexp}
|
* @returns {regexp}
|
||||||
*/
|
*/
|
||||||
std::regex parseStructure(std::string structure) {
|
static std::regex parseStructure(std::string structure) {
|
||||||
std::smatch match;
|
std::smatch match;
|
||||||
|
|
||||||
std::string::const_iterator text_iter = structure.cbegin();
|
std::string::const_iterator text_iter = structure.cbegin();
|
||||||
std::ostringstream result;
|
std::ostringstream result;
|
||||||
|
|
||||||
while (std::regex_search(text_iter, structure.cend(), match,
|
while (std::regex_search(text_iter, structure.cend(), match, std::regex("(.{3})"))) {
|
||||||
std::regex("(.{3})"))) {
|
|
||||||
std::string format;
|
std::string format;
|
||||||
char pattern = match[0].str()[0];
|
char pattern = match[0].str()[0];
|
||||||
int repeats = std::stoi((match[0].str().substr(1)));
|
int repeats = std::stoi((match[0].str().substr(1)));
|
||||||
|
@ -124,320 +152,225 @@ std::regex parseStructure(std::string structure) {
|
||||||
return std::regex(regex.c_str());
|
return std::regex(regex.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Validate::isValid(std::string arg) {
|
bool Validate::isValid(std::string account) {
|
||||||
Specification* spec = new Specification(arg);
|
|
||||||
|
|
||||||
/* Convert uppercase */
|
/* Convert uppercase */
|
||||||
std::transform(spec->example.begin(), spec->example.end(),
|
std::transform(account.begin(), account.end(), account.begin(), toupper);
|
||||||
spec->example.begin(), toupper);
|
|
||||||
|
/* Reject anything too small */
|
||||||
|
if (account.length() < 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Match on country */
|
/* Match on country */
|
||||||
spec->countryCode = spec->example.substr(0, 2);
|
const std::string& countryCode = account.substr(0, 2);
|
||||||
spec->length = spec->example.length();
|
const std::string& shortened = account.substr(4);
|
||||||
Specification* specFound = this->specifications[spec->countryCode];
|
|
||||||
if (!specFound)
|
const std::unique_ptr<Specification>& specFound = specifications[countryCode];
|
||||||
|
if (!specFound) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Test accountnumber */
|
/* Test accountnumber */
|
||||||
std::string shortened = spec->example.substr(4, spec->example.length());
|
return specFound->getLength() == account.length()
|
||||||
bool result = specFound->length == spec->length
|
|
||||||
&& specFound->countryCode.compare(spec->countryCode) == 0
|
|
||||||
&& std::regex_match(shortened, parseStructure(specFound->structure))
|
&& std::regex_match(shortened, parseStructure(specFound->structure))
|
||||||
&& iso7064Mod97_10(spec->example);
|
&& iso7064Mod97_10(account);
|
||||||
|
|
||||||
delete spec;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Validate::~Validate() {
|
|
||||||
for (auto it = specifications.begin(); it != specifications.end(); it++) {
|
|
||||||
delete it->second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Validate::Validate() {
|
Validate::Validate() {
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"AD", 24, "F04F04A12",
|
"AD", 24, "F04F04A12");
|
||||||
"AD1200012030200359100100"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"AE", 23, "F03F16");
|
||||||
"AE", 23, "F03F16",
|
addSpecification(
|
||||||
"AE070331234567890123456"));
|
"AL", 28, "F08A16");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"AL", 28, "F08A16",
|
"AT", 20, "F05F11");
|
||||||
"AL47212110090000000235698741"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"AZ", 28, "U04A20");
|
||||||
"AT", 20, "F05F11",
|
addSpecification(
|
||||||
"AT611904300234573201"));
|
"BA", 20, "F03F03F08F02");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"AZ", 28, "U04A20",
|
"BE", 16, "F03F07F02");
|
||||||
"AZ21NABZ00000000137010001944"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"BG", 22, "U04F04F02A08");
|
||||||
"BA", 20, "F03F03F08F02",
|
addSpecification(
|
||||||
"BA391290079401028494"));
|
"BH", 22, "U04A14");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"BE", 16, "F03F07F02",
|
"BR", 29, "F08F05F10U01A01");
|
||||||
"BE68539007547034"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"CH", 21, "F05A12");
|
||||||
"BG", 22, "U04F04F02A08",
|
addSpecification(
|
||||||
"BG80BNBG96611020345678"));
|
"CR", 21, "F03F14");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"BH", 22, "U04A14",
|
"CY", 28, "F03F05A16");
|
||||||
"BH67BMAG00001299123456"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"CZ", 24, "F04F06F10");
|
||||||
"BR", 29, "F08F05F10U01A01",
|
addSpecification(
|
||||||
"BR9700360305000010009795493P1"));
|
"DE", 22, "F08F10");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"CH", 21, "F05A12",
|
"DK", 18, "F04F09F01");
|
||||||
"CH9300762011623852957"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"DO", 28, "U04F20");
|
||||||
"CR", 21, "F03F14",
|
addSpecification(
|
||||||
"CR0515202001026284066"));
|
"EE", 20, "F02F02F11F01");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"CY", 28, "F03F05A16",
|
"ES", 24, "F04F04F01F01F10");
|
||||||
"CY17002001280000001200527600"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"FI", 18, "F06F07F01");
|
||||||
"CZ", 24, "F04F06F10",
|
addSpecification(
|
||||||
"CZ6508000000192000145399"));
|
"FO", 18, "F04F09F01");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"DE", 22, "F08F10",
|
"FR", 27, "F05F05A11F02");
|
||||||
"DE89370400440532013000"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"GB", 22, "U04F06F08");
|
||||||
"DK", 18, "F04F09F01",
|
addSpecification(
|
||||||
"DK5000400440116243"));
|
"GE", 22, "U02F16");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"DO", 28, "U04F20",
|
"GI", 23, "U04A15");
|
||||||
"DO28BAGR00000001212453611324"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"GL", 18, "F04F09F01");
|
||||||
"EE", 20, "F02F02F11F01",
|
addSpecification(
|
||||||
"EE382200221020145685"));
|
"GR", 27, "F03F04A16");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"ES", 24, "F04F04F01F01F10",
|
"GT", 28, "A04A20");
|
||||||
"ES9121000418450200051332"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"HR", 21, "F07F10");
|
||||||
"FI", 18, "F06F07F01",
|
addSpecification(
|
||||||
"FI2112345600000785"));
|
"HU", 28, "F03F04F01F15F01");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"FO", 18, "F04F09F01",
|
"IE", 22, "U04F06F08");
|
||||||
"FO6264600001631634"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"IL", 23, "F03F03F13");
|
||||||
"FR", 27, "F05F05A11F02",
|
addSpecification(
|
||||||
"FR1420041010050500013M02606"));
|
"IS", 26, "F04F02F06F10");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"GB", 22, "U04F06F08",
|
"IT", 27, "U01F05F05A12");
|
||||||
"GB29NWBK60161331926819"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"KW", 30, "U04A22");
|
||||||
"GE", 22, "U02F16",
|
addSpecification(
|
||||||
"GE29NB0000000101904917"));
|
"KZ", 20, "F03A13");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"GI", 23, "U04A15",
|
"LB", 28, "F04A20");
|
||||||
"GI75NWBK000000007099453"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"LC", 32, "U04F24");
|
||||||
"GL", 18, "F04F09F01",
|
addSpecification(
|
||||||
"GL8964710001000206"));
|
"LI", 21, "F05A12");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"GR", 27, "F03F04A16",
|
"LT", 20, "F05F11");
|
||||||
"GR1601101250000000012300695"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"LU", 20, "F03A13");
|
||||||
"GT", 28, "A04A20",
|
addSpecification(
|
||||||
"GT82TRAJ01020000001210029690"));
|
"LV", 21, "U04A13");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"HR", 21, "F07F10",
|
"MC", 27, "F05F05A11F02");
|
||||||
"HR1210010051863000160"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"MD", 24, "U02A18");
|
||||||
"HU", 28, "F03F04F01F15F01",
|
addSpecification(
|
||||||
"HU42117730161111101800000000"));
|
"ME", 22, "F03F13F02");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"IE", 22, "U04F06F08",
|
"MK", 19, "F03A10F02");
|
||||||
"IE29AIBK93115212345678"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"MR", 27, "F05F05F11F02");
|
||||||
"IL", 23, "F03F03F13",
|
addSpecification(
|
||||||
"IL620108000000099999999"));
|
"MT", 31, "U04F05A18");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"IS", 26, "F04F02F06F10",
|
"MU", 30, "U04F02F02F12F03U03");
|
||||||
"IS140159260076545510730339"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"NL", 18, "U04F10");
|
||||||
"IT", 27, "U01F05F05A12",
|
addSpecification(
|
||||||
"IT60X0542811101000000123456"));
|
"NO", 15, "F04F06F01");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"KW", 30, "U04A22",
|
"PK", 24, "U04A16");
|
||||||
"KW81CBKU0000000000001234560101"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"PL", 28, "F08F16");
|
||||||
"KZ", 20, "F03A13",
|
addSpecification(
|
||||||
"KZ86125KZT5004100100"));
|
"PS", 29, "U04A21");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"LB", 28, "F04A20",
|
"PT", 25, "F04F04F11F02");
|
||||||
"LB62099900000001001901229114"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"RO", 24, "U04A16");
|
||||||
"LC", 32, "U04F24",
|
addSpecification(
|
||||||
"LC07HEMM000100010012001200013015"));
|
"RS", 22, "F03F13F02");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"LI", 21, "F05A12",
|
"SA", 24, "F02A18");
|
||||||
"LI21088100002324013AA"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"SE", 24, "F03F16F01");
|
||||||
"LT", 20, "F05F11",
|
addSpecification(
|
||||||
"LT121000011101001000"));
|
"SI", 19, "F05F08F02");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"LU", 20, "F03A13",
|
"SK", 24, "F04F06F10");
|
||||||
"LU280019400644750000"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"SM", 27, "U01F05F05A12");
|
||||||
"LV", 21, "U04A13",
|
addSpecification(
|
||||||
"LV80BANK0000435195001"));
|
"ST", 25, "F08F11F02");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"MC", 27, "F05F05A11F02",
|
"TL", 23, "F03F14F02");
|
||||||
"MC5811222000010123456789030"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"TN", 24, "F02F03F13F02");
|
||||||
"MD", 24, "U02A18",
|
addSpecification(
|
||||||
"MD24AG000225100013104168"));
|
"TR", 26, "F05F01A16");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"ME", 22, "F03F13F02",
|
"VG", 24, "U04F16");
|
||||||
"ME25505000012345678951"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"XK", 20, "F04F10F02");
|
||||||
"MK", 19, "F03A10F02",
|
addSpecification(
|
||||||
"MK07250120000058984"));
|
"AO", 25, "F21");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"MR", 27, "F05F05F11F02",
|
"BF", 27, "F23");
|
||||||
"MR1300020001010000123456753"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"BI", 16, "F12");
|
||||||
"MT", 31, "U04F05A18",
|
addSpecification(
|
||||||
"MT84MALT011000012345MTLCAST001S"));
|
"BJ", 28, "F24");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"MU", 30, "U04F02F02F12F03U03",
|
"CI", 28, "U01F23");
|
||||||
"MU17BOMM0101101030300200000MUR"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"CM", 27, "F23");
|
||||||
"NL", 18, "U04F10",
|
addSpecification(
|
||||||
"NL91ABNA0417164300"));
|
"CV", 25, "F21");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"NO", 15, "F04F06F01",
|
"DZ", 24, "F20");
|
||||||
"NO9386011117947"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"IR", 26, "F22");
|
||||||
"PK", 24, "U04A16",
|
addSpecification(
|
||||||
"PK36SCBL0000001123456702"));
|
"JO", 30, "A04F22");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"PL", 28, "F08F16",
|
"MG", 27, "F23");
|
||||||
"PL61109010140000071219812874"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"ML", 28, "U01F23");
|
||||||
"PS", 29, "U04A21",
|
addSpecification(
|
||||||
"PS92PALS000000000400123456702"));
|
"MZ", 25, "F21");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"PT", 25, "F04F04F11F02",
|
"QA", 29, "U04A21");
|
||||||
"PT50000201231234567890154"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"SN", 28, "U01F23");
|
||||||
"RO", 24, "U04A16",
|
addSpecification(
|
||||||
"RO49AAAA1B31007593840000"));
|
"UA", 29, "F25");
|
||||||
addSpecification(new Specification(
|
addSpecification(
|
||||||
"RS", 22, "F03F13F02",
|
"EG", 27, "F23");
|
||||||
"RS35260005601001611379"));
|
addSpecification(
|
||||||
addSpecification(new Specification(
|
"CG", 27, "F23");
|
||||||
"SA", 24, "F02A18",
|
addSpecification(
|
||||||
"SA0380000000608010167519"));
|
"GA", 27, "F23");
|
||||||
addSpecification(new Specification(
|
|
||||||
"SE", 24, "F03F16F01",
|
|
||||||
"SE4550000000058398257466"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"SI", 19, "F05F08F02",
|
|
||||||
"SI56263300012039086"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"SK", 24, "F04F06F10",
|
|
||||||
"SK3112000000198742637541"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"SM", 27, "U01F05F05A12",
|
|
||||||
"SM86U0322509800000000270100"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"ST", 25, "F08F11F02",
|
|
||||||
"ST68000100010051845310112"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"TL", 23, "F03F14F02",
|
|
||||||
"TL380080012345678910157"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"TN", 24, "F02F03F13F02",
|
|
||||||
"TN5910006035183598478831"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"TR", 26, "F05F01A16",
|
|
||||||
"TR330006100519786457841326"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"VG", 24, "U04F16",
|
|
||||||
"VG96VPVG0000012345678901"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"XK", 20, "F04F10F02",
|
|
||||||
"XK051212012345678906"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"AO", 25, "F21",
|
|
||||||
"AO69123456789012345678901"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"BF", 27, "F23",
|
|
||||||
"BF2312345678901234567890123"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"BI", 16, "F12",
|
|
||||||
"BI41123456789012"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"BJ", 28, "F24",
|
|
||||||
"BJ39123456789012345678901234"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"CI", 28, "U01F23",
|
|
||||||
"CI17A12345678901234567890123"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"CM", 27, "F23",
|
|
||||||
"CM9012345678901234567890123"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"CV", 25, "F21",
|
|
||||||
"CV30123456789012345678901"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"DZ", 24, "F20",
|
|
||||||
"DZ8612345678901234567890"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"IR", 26, "F22",
|
|
||||||
"IR861234568790123456789012"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"JO", 30, "A04F22",
|
|
||||||
"JO15AAAA1234567890123456789012"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"MG", 27, "F23",
|
|
||||||
"MG1812345678901234567890123"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"ML", 28, "U01F23",
|
|
||||||
"ML15A12345678901234567890123"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"MZ", 25, "F21",
|
|
||||||
"MZ25123456789012345678901"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"QA", 29, "U04A21",
|
|
||||||
"QA30AAAA123456789012345678901"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"SN", 28, "U01F23",
|
|
||||||
"SN52A12345678901234567890123"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"UA", 29, "F25",
|
|
||||||
"UA511234567890123456789012345"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"EG", 27, "F23",
|
|
||||||
"EG1100006001880800100014553"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"CG", 27, "F23",
|
|
||||||
"CG5230011000202151234567890"));
|
|
||||||
addSpecification(new Specification(
|
|
||||||
"GA", 27, "F23",
|
|
||||||
"GA2140002000055602673300064"));
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Separate CXX and C logic to minimize unexpected or malformed symbols due to
|
* Separate CXX and C logic to minimize unexpected or malformed symbols due to
|
||||||
* language conversions. Also catch all exceptions the std++ can throw since
|
* language conversions. Also demark all exceptions the std++ can throw since
|
||||||
* PostgreSQL is not able to handle them.
|
* PostgreSQL is not able to handle them.
|
||||||
*
|
*
|
||||||
* @param {string} iban
|
* @param {string} iban
|
||||||
* @returns {bool}
|
* @returns {bool}
|
||||||
*/
|
*/
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
bool account_validate_text(text *iban) {
|
bool account_validate_text(text *iban) {
|
||||||
char *ciban;
|
char *ciban;
|
||||||
bool result;
|
bool result;
|
||||||
Validate val;
|
|
||||||
|
|
||||||
ciban = text_to_cstring(iban);
|
ciban = text_to_cstring(iban);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = val.isValid(std::string(ciban));
|
result = validator.isValid(ciban);
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
elog(ERROR, "%s", e.what());
|
elog(ERROR, "%s", e.what());
|
||||||
return false;
|
return false;
|
||||||
|
@ -448,10 +381,9 @@ bool account_validate_text(text *iban) {
|
||||||
|
|
||||||
bool account_validate_str(char *iban) {
|
bool account_validate_str(char *iban) {
|
||||||
bool result;
|
bool result;
|
||||||
Validate val;
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
result = val.isValid(std::string(iban));
|
result = validator.isValid(iban);
|
||||||
} catch (std::exception& e) {
|
} catch (std::exception& e) {
|
||||||
elog(ERROR, "%s", e.what());
|
elog(ERROR, "%s", e.what());
|
||||||
return false;
|
return false;
|
||||||
|
@ -459,82 +391,89 @@ bool account_validate_str(char *iban) {
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
/**************************************************************************
|
|
||||||
* Input/Output functions
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(ibanin);
|
PG_MODULE_MAGIC;
|
||||||
|
|
||||||
Datum
|
typedef char Iban;
|
||||||
ibanin(PG_FUNCTION_ARGS) {
|
|
||||||
char *inputText = PG_GETARG_CSTRING(0);
|
|
||||||
|
|
||||||
if (!account_validate_str(inputText))
|
/**************************************************************************
|
||||||
ereport(ERROR,
|
* Input/Output functions
|
||||||
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
**************************************************************************/
|
||||||
errmsg("invalid iban format for value: \"%s\"",
|
|
||||||
inputText)));
|
|
||||||
|
|
||||||
PG_RETURN_TEXT_P(cstring_to_text(inputText));
|
PG_FUNCTION_INFO_V1(ibanin);
|
||||||
}
|
|
||||||
|
|
||||||
/* Convert type output */
|
Datum
|
||||||
|
ibanin(PG_FUNCTION_ARGS) {
|
||||||
|
char *inputText = PG_GETARG_CSTRING(0);
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(ibanout);
|
if (!account_validate_str(inputText))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
|
||||||
|
errmsg("invalid iban format for value: \"%s\"",
|
||||||
|
inputText)));
|
||||||
|
|
||||||
Datum
|
PG_RETURN_TEXT_P(cstring_to_text(inputText));
|
||||||
ibanout(PG_FUNCTION_ARGS) {
|
|
||||||
Iban *iban = (Iban *) PG_GETARG_DATUM(0);
|
|
||||||
|
|
||||||
PG_RETURN_CSTRING(TextDatumGetCString(iban));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**************************************************************************
|
|
||||||
* Binary Input/Output functions
|
|
||||||
**************************************************************************/
|
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(ibanrecv);
|
|
||||||
|
|
||||||
Datum
|
|
||||||
ibanrecv(PG_FUNCTION_ARGS) {
|
|
||||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
||||||
text *result;
|
|
||||||
Iban *str;
|
|
||||||
int nbytes;
|
|
||||||
|
|
||||||
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
|
|
||||||
|
|
||||||
result = cstring_to_text_with_len(str, nbytes);
|
|
||||||
pfree(str);
|
|
||||||
PG_RETURN_TEXT_P(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(ibansend);
|
|
||||||
|
|
||||||
Datum
|
|
||||||
ibansend(PG_FUNCTION_ARGS) {
|
|
||||||
text *t = PG_GETARG_TEXT_PP(0);
|
|
||||||
StringInfoData buf;
|
|
||||||
|
|
||||||
pq_begintypsend(&buf);
|
|
||||||
pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
|
|
||||||
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Manually verify a text */
|
|
||||||
|
|
||||||
PG_FUNCTION_INFO_V1(iban_validate);
|
|
||||||
|
|
||||||
Datum
|
|
||||||
iban_validate(PG_FUNCTION_ARGS) {
|
|
||||||
text *iban = PG_GETARG_TEXT_P(0);
|
|
||||||
|
|
||||||
bool result = account_validate_text(iban);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert type output */
|
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(ibanout);
|
||||||
|
|
||||||
|
Datum
|
||||||
|
ibanout(PG_FUNCTION_ARGS) {
|
||||||
|
Iban *iban = (Iban *) PG_GETARG_DATUM(0);
|
||||||
|
|
||||||
|
PG_RETURN_CSTRING(TextDatumGetCString(iban));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************************
|
||||||
|
* Binary Input/Output functions
|
||||||
|
**************************************************************************/
|
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(ibanrecv);
|
||||||
|
|
||||||
|
Datum
|
||||||
|
ibanrecv(PG_FUNCTION_ARGS) {
|
||||||
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
||||||
|
text *result;
|
||||||
|
Iban *str;
|
||||||
|
int nbytes;
|
||||||
|
|
||||||
|
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
|
||||||
|
|
||||||
|
result = cstring_to_text_with_len(str, nbytes);
|
||||||
|
pfree(str);
|
||||||
|
PG_RETURN_TEXT_P(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(ibansend);
|
||||||
|
|
||||||
|
Datum
|
||||||
|
ibansend(PG_FUNCTION_ARGS) {
|
||||||
|
text *t = PG_GETARG_TEXT_PP(0);
|
||||||
|
StringInfoData buf;
|
||||||
|
|
||||||
|
pq_begintypsend(&buf);
|
||||||
|
pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t));
|
||||||
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Manually verify a text */
|
||||||
|
|
||||||
|
PG_FUNCTION_INFO_V1(iban_validate);
|
||||||
|
|
||||||
|
Datum
|
||||||
|
iban_validate(PG_FUNCTION_ARGS) {
|
||||||
|
text *iban = PG_GETARG_TEXT_P(0);
|
||||||
|
|
||||||
|
bool result = account_validate_text(iban);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class Specification {
|
|
||||||
public:
|
|
||||||
Specification(std::string countryCode, int length, std::string structure, std::string example) :
|
|
||||||
countryCode(countryCode),
|
|
||||||
length(length),
|
|
||||||
structure(structure),
|
|
||||||
example(example) {
|
|
||||||
};
|
|
||||||
Specification(std::string example) : example(example) {};
|
|
||||||
std::string countryCode;
|
|
||||||
int length;
|
|
||||||
std::string structure;
|
|
||||||
std::string example;
|
|
||||||
};
|
|
14
validate.h
14
validate.h
|
@ -1,14 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <memory>
|
|
||||||
#include <map>
|
|
||||||
#include "specification.h"
|
|
||||||
|
|
||||||
class Validate {
|
|
||||||
public:
|
|
||||||
Validate();
|
|
||||||
~Validate();
|
|
||||||
bool isValid(std::string arg);
|
|
||||||
void addSpecification(Specification* specPtr);
|
|
||||||
|
|
||||||
std::map<std::string, Specification*> specifications;
|
|
||||||
};
|
|
Loading…
Reference in New Issue