После реализации nodejs приложения возникла задача его демонизации. Один из способов - использование модуля, разработанного nodejitsu - forever. Для установки данного модуля воспользуйтесь командой (Ubuntu Server):
sudo npm -g install forever
После этого можно запустить выполнение вашего nodejs приложения с помощью forever в виде самостоятельного сервиса:
forever start /path/to/directory/containing_your_app/your_app_name.js
forever будет отслеживать за падениями приложения и пытаться его поднять. В случае же рестарта системы, запуска вашего сервиса не произойдет. Здесь нужно реализовать автозагрузку на уровне системы. Создайте скрипт запуска в директории /etc/init.d. Ниже приведен пример скрипта автозапуска /etc/init.d/your_app_name:
#!/bin/bash
#
# description: your_app_name (node) service
#
# use commands:
# service your_app_name <command (start|stop|status|restart)>
SERVICE_NAME=your_app_name
SOURCE_DIR=/path/to/directory/containing_your_app
SOURCE_NAME=your_app_name.js
SOURCE_PATH=$SOURCE_DIR/$SOURCE_NAME
LOG_DIR=$SOURCE_DIR/forever
USER=tester
pidfile=/home/$USER/.forever/pids/$SERVICE_NAME.pid
logfile=$LOG_DIR/forever.log
outfile=$LOG_DIR/output.log
errfile=$LOG_DIR/error.log
case "$1" in
start)
forever start -l $logfile -o $outfile -e $errfile --pidFile $pidfile -a $SOURCE_PATH
;;
stop)
forever stop --pidFile $pidfile $SOURCE_PATH
;;
status)
forever list
;;
restart)
forever restart -l $logfile -o $outfile -e $errfile --pidFile $pidfile -a $SOURCE_PATH
;;
*)
echo "Usage: $SERVICE_NAME {start|stop|status|restart}"
exit 1
;;
esac
exit 0
Далее выдайте права:
sudo chmod 755 /etc/init.d/your_app_name
и пропишите его в автозагрузку:
sudo update-rc.d your_app_name defaults
Oracle. ORA-21561: OID generation failed
После установки клиента при попытке коннекта выбрасывается следующая ошибка
Для устранения необходимо добавить имя хоста в файл hosts:
$ hostname
$ nano /etc/hosts
> 127.0.0.1 localhost hostname
PLSQL. JSON validator (string validation)
Как известно, JSON формат представляет собой альтернативу XML формату. В настоящее время данный формат получил довольно широкое распространение. Так же и Oracle не отстает от времени и в версии 12.1.0.2 была добавлена нативная поддержка JSON формата. Если Вы работаете на более поздних версиях, то можно добавить собственные реализации для поддержки формата. Есть уже и готовые решения, например можно воспользоваться следующим ресурсом - https://github.com/pljson/pljson.
В моем же случае все немного проще. На стороне сервера по триггеру запускался обработчик, который формировал данные в строковом виде в JSON формате и после отправлял POST запросом на определенный ресурс. Перед отправкой необходимо было убедиться в валидности JSON формата. Так возникла потребность в организации такого рода JSON валидатора. За основу был взят JSON парсер, написанный Дугласом Крокфордом на javascript, с которым можно ознакомиться по ссылке - https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js. Данный парсер предоставляет альтернативу встроенному парсеру JSON.parse в случае отсутствия поддержки оного в Вашем браузере. Ниже представлена реализация тела пакета данного валидатора. В спецификации внешний доступ предоставлен трем методам:
function unsafety_validate(source in varchar2) return boolean;
function safety_validate(source in varchar2) return boolean;
function safety_validate(source in varchar2, errmsg in out varchar2) return boolean;
Префиксы - safety и unsafety - указывают на возможность генерирования возникающих в ходе валидации исключений. С полным описанием пакета можно ознакомиться по ссылке - https://github.com/mozg1984/PL-JSON-VALIDATOR.
create or replace package body json_validator is
/* @private
* type for instantiate keys storages
*/
type array_t is table of varchar2(1000);
atCh integer; -- the index of the current character
ch char; -- the current character
text varchar2(32767);
/* @private
* call error when something is wrong
*/
procedure error(m in varchar2 default '')
is
errmsg varchar2(32767);
begin
errmsg := 'name: SyntaxError, ';
errmsg := errmsg || 'message: ' || m || ', ';
errmsg := errmsg || 'at: ' || atCh || ', ';
errmsg := errmsg || 'text: ' || text;
raise_application_error(-20000, errmsg);
end;
/* @private
* escape sequence
*/
function escapee(ch in char default '') return varchar2
is
begin
case ch
when '"' then return '"';
when '\' then return '\';
when '/' then return '/';
when 'b' then return '\b';
when 'f' then return '\f';
when 'n' then return '\n';
when 'r' then return '\r';
when 't' then return '\t';
else return null;
end case;
end;
/* @private
* add key to keys storage
*/
procedure add_key(p_array in out nocopy array_t, p_key in varchar2)
is
begin
p_array.extend();
p_array(p_array.count()) := p_key;
exception
when collection_is_null then
p_array := array_t(p_key);
end;
/* @private
* check duplicate keys in keys storage
*/
function has_key(p_array in out nocopy array_t, p_key in varchar2) return boolean
is
is_equal boolean := false;
begin
for i in p_array.first..p_array.last loop
if p_array(i) = p_key then
is_equal := true;
end if;
end loop;
return is_equal;
exception
when collection_is_null then
return is_equal;
end;
/* @private
* get char from string by index position
*/
function charAt(str in varchar2, pos in integer) return char
is
begin
return substr(str, pos, 1);
end;
/* @private
* check if given number
*/
function isNumber(num in varchar2) return boolean
is
begin
case regexp_like(num, '^\d*\.?\d+$')
when true then
return true;
else
return false;
end case;
end;
/* @private
* check if given character
*/
function exist(ch in varchar2 default '') return boolean
is
begin
return ch is not null;
end;
/* @private
* convert hex number (character) to decimal number
*/
function hex2dec(ch in char) return number
is
begin
return to_number(ch, 'x');
exception
when value_error then
return null;
end;
/* @private
* convert hex code to unicode character
*/
function getUnicodeChar(hexcode in varchar2) return varchar2
is
begin
return trim(unistr('\' || hexcode || ' '));
exception
when others then
return '';
end;
/* @private
* get the next character
*/
function nextChar(c in char default '') return char
is
begin
-- if a c parameter is provided, verify that it matches the current character
if (exist(c) and c != ch) then
error('Expected ''' || c || ''' instead of ''' || ch || '''');
end if;
-- when there are no more characters, return the empty string
ch := charAt(text, atCh);
atCh := atCh + 1;
return ch;
end;
/* @private
* move current char to next
*/
procedure nextChar(c in char default '')
is
begin
-- if a c parameter is provided, verify that it matches the current character
if (exist(c) and c != ch) then
error('Expected ''' || c || ''' instead of ''' || ch || '''');
end if;
ch := charAt(text, atCh);
atCh := atCh + 1;
end;
/* @private
* forward declaration of common validate function
*/
function validate return boolean;
/* @private
* validate a number value
*/
function validateNumber return boolean
is
l_number varchar2(32767) := '';
begin
if (ch = '-') then
l_number := '-';
nextChar('-');
end if;
while (ch >= '0' and ch <= '9') loop
l_number := l_number || ch;
nextChar();
end loop;
if (ch = '.') then
l_number := l_number || '.';
while (exist(nextChar()) and ch >= '0' and ch <= '9') loop
l_number := l_number || ch;
end loop;
end if;
if (ch = 'e' or ch = 'E') then
l_number := l_number || ch;
nextChar();
if (ch = '-' or ch = '+') then
l_number := l_number || ch;
nextChar();
end if;
while (ch >= '0' and ch <= '9') loop
l_number := l_number || ch;
nextChar();
end loop;
end if;
if (not(isNumber(l_number))) then
error('Bad number');
else
return true;
end if;
end;
/* @private
* validate a string value
*/
function validateString return boolean
is
decnum number;
begin
-- when parsing for string values, we must look for " and \ characters
if (ch = '"') then
while (exist(nextChar())) loop
if (ch = '"') then
nextChar();
return true;
end if;
if (ch = '\') then
nextChar();
if (ch = 'u') then
for i in 1..4 loop
decnum := hex2dec(nextChar());
if (not isNumber(decnum)) then
error('Malformed Unicode character escape sequence');
end if;
end loop;
elsif (escapee(ch) is not null) then
null;
else
exit;
end if;
end if;
end loop;
end if;
error('Bad string');
end;
/* @private
* get string key value (for checking duplicate keys in object value)
*/
function stringKey return varchar2
is
l_string varchar2(32767) := '';
decnum number;
uffff varchar2(32767);
begin
-- when parsing for string values, we must look for " and \ characters
if (ch = '"') then
while (exist(nextChar())) loop
if (ch = '"') then
nextChar();
return l_string;
end if;
if (ch = '\') then
nextChar();
if (ch = 'u') then
uffff := '';
for i in 1..4 loop
decnum := hex2dec(nextChar());
if (not isNumber(decnum)) then
error('Malformed Unicode character escape sequence');
end if;
uffff := uffff || ch;
end loop;
l_string := l_string || getUnicodeChar(uffff);
elsif (escapee(ch) is not null) then
l_string := l_string || escapee(ch);
else
exit;
end if;
else
l_string := l_string || ch;
end if;
end loop;
end if;
error('Bad string');
end;
/* @private
* skip whitespace
*/
procedure white
is
begin
while (exist(ch) and ch <= ' ') loop
nextChar();
end loop;
end;
/* @private
* validate a word (true, false or null)
*/
function validateWord return boolean
is
begin
case ch
when 't' then
nextChar('t');
nextChar('r');
nextChar('u');
nextChar('e');
return true;
when 'f' then
nextChar('f');
nextChar('a');
nextChar('l');
nextChar('s');
nextChar('e');
return true;
when 'n' then
nextChar('n');
nextChar('u');
nextChar('l');
nextChar('l');
return true;
else
error('Unexpected ''' || ch || '''');
end case;
end;
/* @private
* validate an array value
*/
function validateArray return boolean
is
l_result boolean := true;
begin
if (ch = '[') then
nextChar('[');
white();
if (ch = ']') then
nextChar(']');
return l_result; -- empty array
end if;
while (exist(ch)) loop
l_result := validate();
white();
if (ch = ']') then
nextChar(']');
return l_result;
end if;
nextChar(',');
white();
end loop;
end if;
error('Bad array');
end;
/* @private
* validate an object value
*/
function validateObject return boolean
is
l_result boolean := true;
l_key varchar2(1000);
l_keys array_t;
begin
if (ch = '{') then
nextChar('{');
white();
if (ch = '}') then
nextChar('}');
return l_result; -- empty object
end if;
while (exist(ch)) loop
l_key := stringKey();
white();
nextChar(':');
if (has_key(l_keys, l_key)) then
error('Duplicate key "' || l_key || '"');
end if;
add_key(l_keys, l_key);
l_result := validate();
white();
if (ch = '}') then
nextChar('}');
return l_result;
end if;
nextChar(',');
white();
end loop;
end if;
error('Bad object');
end;
/* @public
* validate a JSON value.
* It could be an object, an array, a string, a number, or a word.
*/
function validate return boolean
is
begin
white();
case ch
when '{' then
return validateObject();
when '[' then
return validateArray();
when '"' then
return validateString();
when '-' then
return validateNumber();
else
return case
when (ch >= '0' and ch <= '9') then validateNumber() else validateWord() end;
end case;
end;
/* @public
* unsafety validate JSON string (throw exception ora-20000)
*/
function unsafety_validate(source in varchar2) return boolean
is
l_result boolean;
begin
text := source;
atCh := 1;
ch := ' ';
l_result := validate();
white();
if (exist(ch)) then
error('Syntax error');
end if;
return l_result;
end;
/* @public
* safety validate JSON string (catch all exceptions)
*/
function safety_validate(source in varchar2) return boolean
is
l_result boolean;
begin
text := source;
atCh := 1;
ch := ' ';
l_result := validate();
white();
if (exist(ch)) then
error('Syntax error');
end if;
return l_result;
exception
when others then
return false;
end;
/* @public
* safety validate JSON string (catch all exceptions with error message)
*/
function safety_validate(source in varchar2,
errmsg in out varchar2) return boolean
is
l_result boolean;
begin
text := source;
atCh := 1;
ch := ' ';
l_result := validate();
white();
if (exist(ch)) then
error('Syntax error');
end if;
return l_result;
exception
when others then
errmsg := sqlerrm;
return false;
end;
begin
-- init
null;
end json_validator;
В моем же случае все немного проще. На стороне сервера по триггеру запускался обработчик, который формировал данные в строковом виде в JSON формате и после отправлял POST запросом на определенный ресурс. Перед отправкой необходимо было убедиться в валидности JSON формата. Так возникла потребность в организации такого рода JSON валидатора. За основу был взят JSON парсер, написанный Дугласом Крокфордом на javascript, с которым можно ознакомиться по ссылке - https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js. Данный парсер предоставляет альтернативу встроенному парсеру JSON.parse в случае отсутствия поддержки оного в Вашем браузере. Ниже представлена реализация тела пакета данного валидатора. В спецификации внешний доступ предоставлен трем методам:
function unsafety_validate(source in varchar2) return boolean;
function safety_validate(source in varchar2) return boolean;
function safety_validate(source in varchar2, errmsg in out varchar2) return boolean;
Префиксы - safety и unsafety - указывают на возможность генерирования возникающих в ходе валидации исключений. С полным описанием пакета можно ознакомиться по ссылке - https://github.com/mozg1984/PL-JSON-VALIDATOR.
create or replace package body json_validator is
/* @private
* type for instantiate keys storages
*/
type array_t is table of varchar2(1000);
atCh integer; -- the index of the current character
ch char; -- the current character
text varchar2(32767);
/* @private
* call error when something is wrong
*/
procedure error(m in varchar2 default '')
is
errmsg varchar2(32767);
begin
errmsg := 'name: SyntaxError, ';
errmsg := errmsg || 'message: ' || m || ', ';
errmsg := errmsg || 'at: ' || atCh || ', ';
errmsg := errmsg || 'text: ' || text;
raise_application_error(-20000, errmsg);
end;
/* @private
* escape sequence
*/
function escapee(ch in char default '') return varchar2
is
begin
case ch
when '"' then return '"';
when '\' then return '\';
when '/' then return '/';
when 'b' then return '\b';
when 'f' then return '\f';
when 'n' then return '\n';
when 'r' then return '\r';
when 't' then return '\t';
else return null;
end case;
end;
/* @private
* add key to keys storage
*/
procedure add_key(p_array in out nocopy array_t, p_key in varchar2)
is
begin
p_array.extend();
p_array(p_array.count()) := p_key;
exception
when collection_is_null then
p_array := array_t(p_key);
end;
/* @private
* check duplicate keys in keys storage
*/
function has_key(p_array in out nocopy array_t, p_key in varchar2) return boolean
is
is_equal boolean := false;
begin
for i in p_array.first..p_array.last loop
if p_array(i) = p_key then
is_equal := true;
end if;
end loop;
return is_equal;
exception
when collection_is_null then
return is_equal;
end;
/* @private
* get char from string by index position
*/
function charAt(str in varchar2, pos in integer) return char
is
begin
return substr(str, pos, 1);
end;
/* @private
* check if given number
*/
function isNumber(num in varchar2) return boolean
is
begin
case regexp_like(num, '^\d*\.?\d+$')
when true then
return true;
else
return false;
end case;
end;
/* @private
* check if given character
*/
function exist(ch in varchar2 default '') return boolean
is
begin
return ch is not null;
end;
/* @private
* convert hex number (character) to decimal number
*/
function hex2dec(ch in char) return number
is
begin
return to_number(ch, 'x');
exception
when value_error then
return null;
end;
/* @private
* convert hex code to unicode character
*/
function getUnicodeChar(hexcode in varchar2) return varchar2
is
begin
return trim(unistr('\' || hexcode || ' '));
exception
when others then
return '';
end;
/* @private
* get the next character
*/
function nextChar(c in char default '') return char
is
begin
-- if a c parameter is provided, verify that it matches the current character
if (exist(c) and c != ch) then
error('Expected ''' || c || ''' instead of ''' || ch || '''');
end if;
-- when there are no more characters, return the empty string
ch := charAt(text, atCh);
atCh := atCh + 1;
return ch;
end;
/* @private
* move current char to next
*/
procedure nextChar(c in char default '')
is
begin
-- if a c parameter is provided, verify that it matches the current character
if (exist(c) and c != ch) then
error('Expected ''' || c || ''' instead of ''' || ch || '''');
end if;
ch := charAt(text, atCh);
atCh := atCh + 1;
end;
/* @private
* forward declaration of common validate function
*/
function validate return boolean;
/* @private
* validate a number value
*/
function validateNumber return boolean
is
l_number varchar2(32767) := '';
begin
if (ch = '-') then
l_number := '-';
nextChar('-');
end if;
while (ch >= '0' and ch <= '9') loop
l_number := l_number || ch;
nextChar();
end loop;
if (ch = '.') then
l_number := l_number || '.';
while (exist(nextChar()) and ch >= '0' and ch <= '9') loop
l_number := l_number || ch;
end loop;
end if;
if (ch = 'e' or ch = 'E') then
l_number := l_number || ch;
nextChar();
if (ch = '-' or ch = '+') then
l_number := l_number || ch;
nextChar();
end if;
while (ch >= '0' and ch <= '9') loop
l_number := l_number || ch;
nextChar();
end loop;
end if;
if (not(isNumber(l_number))) then
error('Bad number');
else
return true;
end if;
end;
/* @private
* validate a string value
*/
function validateString return boolean
is
decnum number;
begin
-- when parsing for string values, we must look for " and \ characters
if (ch = '"') then
while (exist(nextChar())) loop
if (ch = '"') then
nextChar();
return true;
end if;
if (ch = '\') then
nextChar();
if (ch = 'u') then
for i in 1..4 loop
decnum := hex2dec(nextChar());
if (not isNumber(decnum)) then
error('Malformed Unicode character escape sequence');
end if;
end loop;
elsif (escapee(ch) is not null) then
null;
else
exit;
end if;
end if;
end loop;
end if;
error('Bad string');
end;
/* @private
* get string key value (for checking duplicate keys in object value)
*/
function stringKey return varchar2
is
l_string varchar2(32767) := '';
decnum number;
uffff varchar2(32767);
begin
-- when parsing for string values, we must look for " and \ characters
if (ch = '"') then
while (exist(nextChar())) loop
if (ch = '"') then
nextChar();
return l_string;
end if;
if (ch = '\') then
nextChar();
if (ch = 'u') then
uffff := '';
for i in 1..4 loop
decnum := hex2dec(nextChar());
if (not isNumber(decnum)) then
error('Malformed Unicode character escape sequence');
end if;
uffff := uffff || ch;
end loop;
l_string := l_string || getUnicodeChar(uffff);
elsif (escapee(ch) is not null) then
l_string := l_string || escapee(ch);
else
exit;
end if;
else
l_string := l_string || ch;
end if;
end loop;
end if;
error('Bad string');
end;
/* @private
* skip whitespace
*/
procedure white
is
begin
while (exist(ch) and ch <= ' ') loop
nextChar();
end loop;
end;
/* @private
* validate a word (true, false or null)
*/
function validateWord return boolean
is
begin
case ch
when 't' then
nextChar('t');
nextChar('r');
nextChar('u');
nextChar('e');
return true;
when 'f' then
nextChar('f');
nextChar('a');
nextChar('l');
nextChar('s');
nextChar('e');
return true;
when 'n' then
nextChar('n');
nextChar('u');
nextChar('l');
nextChar('l');
return true;
else
error('Unexpected ''' || ch || '''');
end case;
end;
/* @private
* validate an array value
*/
function validateArray return boolean
is
l_result boolean := true;
begin
if (ch = '[') then
nextChar('[');
white();
if (ch = ']') then
nextChar(']');
return l_result; -- empty array
end if;
while (exist(ch)) loop
l_result := validate();
white();
if (ch = ']') then
nextChar(']');
return l_result;
end if;
nextChar(',');
white();
end loop;
end if;
error('Bad array');
end;
/* @private
* validate an object value
*/
function validateObject return boolean
is
l_result boolean := true;
l_key varchar2(1000);
l_keys array_t;
begin
if (ch = '{') then
nextChar('{');
white();
if (ch = '}') then
nextChar('}');
return l_result; -- empty object
end if;
while (exist(ch)) loop
l_key := stringKey();
white();
nextChar(':');
if (has_key(l_keys, l_key)) then
error('Duplicate key "' || l_key || '"');
end if;
add_key(l_keys, l_key);
l_result := validate();
white();
if (ch = '}') then
nextChar('}');
return l_result;
end if;
nextChar(',');
white();
end loop;
end if;
error('Bad object');
end;
/* @public
* validate a JSON value.
* It could be an object, an array, a string, a number, or a word.
*/
function validate return boolean
is
begin
white();
case ch
when '{' then
return validateObject();
when '[' then
return validateArray();
when '"' then
return validateString();
when '-' then
return validateNumber();
else
return case
when (ch >= '0' and ch <= '9') then validateNumber() else validateWord() end;
end case;
end;
/* @public
* unsafety validate JSON string (throw exception ora-20000)
*/
function unsafety_validate(source in varchar2) return boolean
is
l_result boolean;
begin
text := source;
atCh := 1;
ch := ' ';
l_result := validate();
white();
if (exist(ch)) then
error('Syntax error');
end if;
return l_result;
end;
/* @public
* safety validate JSON string (catch all exceptions)
*/
function safety_validate(source in varchar2) return boolean
is
l_result boolean;
begin
text := source;
atCh := 1;
ch := ' ';
l_result := validate();
white();
if (exist(ch)) then
error('Syntax error');
end if;
return l_result;
exception
when others then
return false;
end;
/* @public
* safety validate JSON string (catch all exceptions with error message)
*/
function safety_validate(source in varchar2,
errmsg in out varchar2) return boolean
is
l_result boolean;
begin
text := source;
atCh := 1;
ch := ' ';
l_result := validate();
white();
if (exist(ch)) then
error('Syntax error');
end if;
return l_result;
exception
when others then
errmsg := sqlerrm;
return false;
end;
begin
-- init
null;
end json_validator;
Пример использования данного пакета
declare
json_string varchar2(1000);
errmsg varchar2(32767);
begin
json_string := '{"number": 123456, "text": "active", "array": [], "object": {}}';
if json_validator.safety_validate(json_string, errmsg) then
dbms_output.put_line('JSON is valid');
else
dbms_output.put_line('JSON is not valid');
dbms_output.put_line(errmsg);
end if;
end;
Javascript. Unicode char by hex code
Ниже представлена реализация получения unicode-символа по шестнадцатеричному коду в методе getUnicodeChar утилитного объекта util.
// utility object
var util = {
// modulo
mod: function (a, b) {
return a % b;
},
// integer division
div: function (a, b) {
return (a - a % b) / b;
},
// convert hex to decimal number
hex2dec: function (hex) {
hex = '' + hex;
var result = 0,
dec, i, len;
for (i = 0, len = hex.length; i < len; i++) {
dec = parseInt(hex.charAt(i), 16);
if (!isFinite(dec)) {
break;
}
result = result * 16 + dec;
}
return result;
},
// convert decimal number to hex
dec2hex: function (number) {
number = +number;
var dec = 0,
result = '',
self = this;
while ((dec = self.mod(number, 16)) > 0) {
result = dec.toString(16) + result;
number = self.div(number, 16);
}
return result;
},
// get unicode char
getUnicodeChar: function (unicode) {
var unicodeChar = '',
uffff = 0,
self = this;
if (unicode.charAt(0) === '\\' && unicode.charAt(1) === 'u') {
uffff = self.hex2dec(unicode.substr(2));
}
return unicodeChar + String.fromCharCode(uffff);
}
};
console.log(util.getUnicodeChar('\\u041a')); // К
console.log(util.hex2dec('041a')); // 1050
console.log(util.dec2hex(1050)); // 41a
Стоит отметить, что методы hex2dec и dec2hex можно реализовать и более простым способом.
// convert hex to decimal number
function hex2dec(hex) {
return parseInt(hex, 16);
}
// convert decimal number to hex
function dec2hex(dec) {
return dec.toString(16);
}
console.log(hex2dec('041a')); // 1050
console.log(dec2hex(1050)); // 41a
// utility object
var util = {
// modulo
mod: function (a, b) {
return a % b;
},
// integer division
div: function (a, b) {
return (a - a % b) / b;
},
// convert hex to decimal number
hex2dec: function (hex) {
hex = '' + hex;
var result = 0,
dec, i, len;
for (i = 0, len = hex.length; i < len; i++) {
dec = parseInt(hex.charAt(i), 16);
if (!isFinite(dec)) {
break;
}
result = result * 16 + dec;
}
return result;
},
// convert decimal number to hex
dec2hex: function (number) {
number = +number;
var dec = 0,
result = '',
self = this;
while ((dec = self.mod(number, 16)) > 0) {
result = dec.toString(16) + result;
number = self.div(number, 16);
}
return result;
},
// get unicode char
getUnicodeChar: function (unicode) {
var unicodeChar = '',
uffff = 0,
self = this;
if (unicode.charAt(0) === '\\' && unicode.charAt(1) === 'u') {
uffff = self.hex2dec(unicode.substr(2));
}
return unicodeChar + String.fromCharCode(uffff);
}
};
console.log(util.getUnicodeChar('\\u041a')); // К
console.log(util.hex2dec('041a')); // 1050
console.log(util.dec2hex(1050)); // 41a
Стоит отметить, что методы hex2dec и dec2hex можно реализовать и более простым способом.
// convert hex to decimal number
function hex2dec(hex) {
return parseInt(hex, 16);
}
// convert decimal number to hex
function dec2hex(dec) {
return dec.toString(16);
}
console.log(hex2dec('041a')); // 1050
console.log(dec2hex(1050)); // 41a
PLSQL. Object type reflection
Возможно ли просматривать начинку объектных типов независимо от их типа. Для этого в Oracle есть поддержка таких универсальных типов как ANYTYPE, ANYDATA и ANYDATASET. Ниже представлен пример рефлексии объектных типов, с элементами типа VARCHAR2, NUMBER и DATE, при желании список поддерживаемых типов можно расширить (см. документацию).
-- sql
create or replace type order_t as object (
order_id number,
order_date date,
description varchar2(1000)
)
-- pl/sql
declare
v_order order_t := order_t(123456, sysdate, 'Description text');
v_anydata anydata;
-- print object information (reflection)
procedure objectInfo(p_object in out anydata) -- out for piecewise
is
l_typecode pls_integer;
l_anytype anytype;
l_result pls_integer;
l_varchar2 varchar2(32767);
l_number number;
l_date date;
-- type-level metadata
type typeinfo_r is record (
prec pls_integer
,scale pls_integer
,len pls_integer
,csid pls_integer
,csfrm pls_integer
,schema_name varchar2(30)
,type_name varchar2(30)
,version varchar2(30)
,count pls_integer
);
typeinfo typeinfo_r;
-- attribute-level metadata
type attrinfo_r is record (
prec pls_integer
,scale pls_integer
,len pls_integer
,csid pls_integer
,csfrm pls_integer
,attr_elt_type anytype
,aname varchar2(32767)
);
attrinfo attrinfo_r;
begin
-- get information for the ANYDATA instance
l_typecode := p_object.getType(l_anytype);
dbms_output.put_line('Typecode: ' || l_typecode);
if l_typecode = dbms_types.typecode_object then -- if given object
p_object.piecewise();
-- get type-level metadata
l_typecode := l_anytype.GetInfo(typeinfo.prec,
typeinfo.scale,
typeinfo.len,
typeinfo.csid,
typeinfo.csfrm,
typeinfo.schema_name,
typeinfo.type_name,
typeinfo.version,
typeinfo.count);
dbms_output.put_line('-------------------------------------');
dbms_output.put_line('Typename: ' || typeinfo.type_name);
dbms_output.put_line('Attributes: ' || typeinfo.count);
for i in 1..typeinfo.count loop -- loop by atrributes
-- get attribute-level metadata
l_typecode := l_anytype.getAttrElemInfo(i,
attrinfo.prec,
attrinfo.scale,
attrinfo.len,
attrinfo.csid,
attrinfo.csfrm,
attrinfo.attr_elt_type,
attrinfo.aname);
dbms_output.put_line('-------------------------------------');
dbms_output.put_line('Attribute: ' || attrinfo.aname);
dbms_output.put_line('Typecode: ' || l_typecode);
dbms_output.put_line('Length: ' || nvl(attrinfo.len, attrinfo.prec));
if l_typecode = dbms_types.typecode_varchar2 then -- varchar2
l_result := p_object.getVarchar2(c => l_varchar2);
dbms_output.put_line('Value: ' || l_varchar2);
elsif l_typecode = dbms_types.typecode_number then -- number
l_result := p_object.getNumber(num => l_number);
dbms_output.put_line('Value: ' || l_number);
elsif l_typecode = dbms_types.typecode_date then -- date
l_result := p_object.getDate(dat => l_date);
dbms_output.put_line('Value: ' || to_char(l_date, 'dd.mm.yyyy'));
else
raise_application_error(-20000, 'Unexpected ' || i || 'st attribute typecode: ' || l_typecode);
end if;
end loop;
end if;
end;
begin
v_anydata := anydata.convertObject(v_order);
objectInfo(v_anydata);
end;
Typecode: 108
-------------------------------------
Typename: ORDER_T
Attributes: 3
-------------------------------------
Attribute: ORDER_ID
Typecode: 2
Length: 0
Value: 123456
-------------------------------------
Attribute: ORDER_DATE
Typecode: 12
Length:
Value: 15.10.2015
-------------------------------------
Attribute: DESCRIPTION
Typecode: 9
Length: 1000
Value: Description text
-- sql
create or replace type order_t as object (
order_id number,
order_date date,
description varchar2(1000)
)
-- pl/sql
declare
v_order order_t := order_t(123456, sysdate, 'Description text');
v_anydata anydata;
-- print object information (reflection)
procedure objectInfo(p_object in out anydata) -- out for piecewise
is
l_typecode pls_integer;
l_anytype anytype;
l_result pls_integer;
l_varchar2 varchar2(32767);
l_number number;
l_date date;
-- type-level metadata
type typeinfo_r is record (
prec pls_integer
,scale pls_integer
,len pls_integer
,csid pls_integer
,csfrm pls_integer
,schema_name varchar2(30)
,type_name varchar2(30)
,version varchar2(30)
,count pls_integer
);
typeinfo typeinfo_r;
-- attribute-level metadata
type attrinfo_r is record (
prec pls_integer
,scale pls_integer
,len pls_integer
,csid pls_integer
,csfrm pls_integer
,attr_elt_type anytype
,aname varchar2(32767)
);
attrinfo attrinfo_r;
begin
-- get information for the ANYDATA instance
l_typecode := p_object.getType(l_anytype);
dbms_output.put_line('Typecode: ' || l_typecode);
if l_typecode = dbms_types.typecode_object then -- if given object
p_object.piecewise();
-- get type-level metadata
l_typecode := l_anytype.GetInfo(typeinfo.prec,
typeinfo.scale,
typeinfo.len,
typeinfo.csid,
typeinfo.csfrm,
typeinfo.schema_name,
typeinfo.type_name,
typeinfo.version,
typeinfo.count);
dbms_output.put_line('-------------------------------------');
dbms_output.put_line('Typename: ' || typeinfo.type_name);
dbms_output.put_line('Attributes: ' || typeinfo.count);
for i in 1..typeinfo.count loop -- loop by atrributes
-- get attribute-level metadata
l_typecode := l_anytype.getAttrElemInfo(i,
attrinfo.prec,
attrinfo.scale,
attrinfo.len,
attrinfo.csid,
attrinfo.csfrm,
attrinfo.attr_elt_type,
attrinfo.aname);
dbms_output.put_line('-------------------------------------');
dbms_output.put_line('Attribute: ' || attrinfo.aname);
dbms_output.put_line('Typecode: ' || l_typecode);
dbms_output.put_line('Length: ' || nvl(attrinfo.len, attrinfo.prec));
if l_typecode = dbms_types.typecode_varchar2 then -- varchar2
l_result := p_object.getVarchar2(c => l_varchar2);
dbms_output.put_line('Value: ' || l_varchar2);
elsif l_typecode = dbms_types.typecode_number then -- number
l_result := p_object.getNumber(num => l_number);
dbms_output.put_line('Value: ' || l_number);
elsif l_typecode = dbms_types.typecode_date then -- date
l_result := p_object.getDate(dat => l_date);
dbms_output.put_line('Value: ' || to_char(l_date, 'dd.mm.yyyy'));
else
raise_application_error(-20000, 'Unexpected ' || i || 'st attribute typecode: ' || l_typecode);
end if;
end loop;
end if;
end;
begin
v_anydata := anydata.convertObject(v_order);
objectInfo(v_anydata);
end;
Typecode: 108
-------------------------------------
Typename: ORDER_T
Attributes: 3
-------------------------------------
Attribute: ORDER_ID
Typecode: 2
Length: 0
Value: 123456
-------------------------------------
Attribute: ORDER_DATE
Typecode: 12
Length:
Value: 15.10.2015
-------------------------------------
Attribute: DESCRIPTION
Typecode: 9
Length: 1000
Value: Description text
oracle v.11.2. Escape and unescape url in cyrillic utf-8
Всем знакомы проблемы с кодировками на кириллице, на Oracle есть замечательный пакет utl_url, который позволяет кодировать символы в utf8 формате. Данный пакет может особо пригодиться, при использовании пакета utl_http во взаимодействии с веб серверами. Попробуйте наладить отправку данных без поддержки этих методов и Вы поймете о чем идет речь. Ниже приведены примеры их использования.
declare
url varchar2(100) := 'http://example.com/?language=русский';
begin
url := utl_url.escape(url, true, 'utf-8');
dbms_output.put_line(url);
url := utl_url.unescape(url, 'utf-8');
dbms_output.put_line(url);
end;
На выходе:
http%3A%2F%2Fexample.com%2F%3Flanguage%3D%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9
http://example.com/?language=русский
declare
url varchar2(100) := 'http://example.com/?language=русский';
begin
url := utl_url.escape(url, true, 'utf-8');
dbms_output.put_line(url);
url := utl_url.unescape(url, 'utf-8');
dbms_output.put_line(url);
end;
На выходе:
http%3A%2F%2Fexample.com%2F%3Flanguage%3D%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9
http://example.com/?language=русский
oracle v.11.2. Get md5 hash
select
lower(dbms_obfuscation_toolkit.md5(input => utl_raw.cast_to_raw('qwerty'))) md5hash
from dual;
d8578edf8458ce06fbc5bb76a58c5ca4
lower(dbms_obfuscation_toolkit.md5(input => utl_raw.cast_to_raw('qwerty'))) md5hash
from dual;
d8578edf8458ce06fbc5bb76a58c5ca4
C. Support private objects in functions
Можно ли добиться поддержки приватности в структурном программировании на C? Javascript может поддерживать приватность за счет техники замыкания, C, конечно, такой возможности не имеет, но можно воспользоваться статическими объектами (с точки зрения класса памяти). Ниже приведен один из подходов
#include <stdio.h>
// init counter action
void init(int *cnt) {
*cnt = 0;
}
// increment counter action
void increment(int *cnt) {
(*cnt)++;
}
// decrement counter action
void decrement(int *cnt) {
(*cnt)--;
}
// show counter action
void show(const int *cnt) {
printf("counter = %d\n", *cnt);
}
// counter encapsulation
void counter(void (*action) (int*)) {
static int cnt = 0; // private
action(&cnt);
}
int main() {
counter(init); // counter = 0;
counter(show); // counter = 0;
counter(increment); // counter = 1;
counter(increment); // counter = 2;
counter(show); // counter = 2;
return 0;
}
В данном случае функции определяют возможные действия над приватным счетчиком, другие действия, как и прямое обращение к значению счетчика (статическая переменная cnt), недопустимы. Можно усложнить данную реализацию для повышения функционала действий над приватным счетчиком. Вот одна из реализаций
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
// check requested init action
int is_init(const char *action) {
return !strcmp(action, "init");
}
// check requested increment action
int is_increment(const char *action) {
return !strcmp(action, "increment");
}
// check requested decrement action
int is_decrement(const char *action) {
return !strcmp(action, "decrement");
}
// check requested show action
int is_show(const char *action) {
return !strcmp(action, "show");
}
// init counter action
void init(int *cnt) {
*cnt = 0;
}
// increment counter action
void increment(int *cnt, int n) {
(*cnt) += n;
}
// decrement counter action
void decrement(int *cnt, int n) {
(*cnt) -= n;
}
// show counter action
void show(const int *cnt) {
printf("counter = %d\n", *cnt);
}
// counter encapsulation
void counter(char *action, ...) {
static int cnt = 0;// private
va_list par;
va_start(par, action);
int n = *((int *) par);// get argument value
*((int *) par) = 0;// clear argument value
va_end(par);
n = n > 1 ? n : 1;
#ifdef DEBUGMODE
printf("debug: action = %s, counter = %d, n = %d\n", action, cnt, n);
#endif
if (is_init(action))
init(&cnt);
else if (is_increment(action))
increment(&cnt, n);
else if (is_decrement(action))
decrement(&cnt, n);
else if (is_show(action))
show(&cnt);
else
printf("unsupported action\n");
}
int main() {
counter("init"); // counter = 0
counter("increment"); // counter = 1
counter("increment"); // counter = 2
counter("show"); // counter = 2
counter("increment", 5); // counter = 7
counter("show"); // counter = 7
counter("decrement"); // counter = 6
counter("show"); // counter = 6
counter("decrement", 3); // counter = 3
counter("show"); // counter = 3
counter("init"); // counter = 0
counter("show"); // counter = 0
counter("test"); // unsupported action
return 0;
}
Или так
#include <stdio.h>
#include <stdarg.h>
// actions
typedef enum {init, increment, decrement, show, test} actions;
// check requested init action
int is_init(actions action) {
return action == init;
}
// check requested increment action
int is_increment(actions action) {
return action == increment;
}
// check requested decrement action
int is_decrement(actions action) {
return action == decrement;
}
// check requested show action
int is_show(actions action) {
return action == show;
}
// init counter action
void init_action(int *cnt) {
*cnt = 0;
}
// increment counter action
void increment_action(int *cnt, int n) {
(*cnt) += n;
}
// decrement counter action
void decrement_action(int *cnt, int n) {
(*cnt) -= n;
}
// show counter action
void show_action(const int *cnt) {
printf("counter = %d\n", *cnt);
}
// counter encapsulation
void counter(actions action, ...) {
static int cnt = 0; // private
va_list par;
va_start(par, action);
int n = *((int *) par);// get argument value
*((int *) par) = 0;// clear argument value
va_end(par);
n = n > 1 ? n : 1;
#ifdef DEBUGMODE
printf("debug: action = %s, counter = %d, n = %d\n", action, cnt, n);
#endif
if (is_init(action))
init_action(&cnt);
else if (is_increment(action))
increment_action(&cnt, n);
else if (is_decrement(action))
decrement_action(&cnt, n);
else if (is_show(action))
show_action(&cnt);
else
printf("unsupported action\n");
}
int main() {
counter(init); // counter = 0
counter(increment); // counter = 1
counter(increment); // counter = 2
counter(show); // counter = 2
counter(increment, 5); // counter = 7
counter(show); // counter = 7
counter(decrement); // counter = 6
counter(show); // counter = 6
counter(decrement, 3); // counter = 3
counter(show); // counter = 3
counter(init); // counter = 0
counter(show); // counter = 0
counter(test); // unsupported action
return 0;
}
#include <stdio.h>
// init counter action
void init(int *cnt) {
*cnt = 0;
}
// increment counter action
void increment(int *cnt) {
(*cnt)++;
}
// decrement counter action
void decrement(int *cnt) {
(*cnt)--;
}
// show counter action
void show(const int *cnt) {
printf("counter = %d\n", *cnt);
}
// counter encapsulation
void counter(void (*action) (int*)) {
static int cnt = 0; // private
action(&cnt);
}
int main() {
counter(init); // counter = 0;
counter(show); // counter = 0;
counter(increment); // counter = 1;
counter(increment); // counter = 2;
counter(show); // counter = 2;
return 0;
}
В данном случае функции определяют возможные действия над приватным счетчиком, другие действия, как и прямое обращение к значению счетчика (статическая переменная cnt), недопустимы. Можно усложнить данную реализацию для повышения функционала действий над приватным счетчиком. Вот одна из реализаций
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
// check requested init action
int is_init(const char *action) {
return !strcmp(action, "init");
}
// check requested increment action
int is_increment(const char *action) {
return !strcmp(action, "increment");
}
// check requested decrement action
int is_decrement(const char *action) {
return !strcmp(action, "decrement");
}
// check requested show action
int is_show(const char *action) {
return !strcmp(action, "show");
}
// init counter action
void init(int *cnt) {
*cnt = 0;
}
// increment counter action
void increment(int *cnt, int n) {
(*cnt) += n;
}
// decrement counter action
void decrement(int *cnt, int n) {
(*cnt) -= n;
}
// show counter action
void show(const int *cnt) {
printf("counter = %d\n", *cnt);
}
// counter encapsulation
void counter(char *action, ...) {
static int cnt = 0;// private
va_list par;
va_start(par, action);
int n = *((int *) par);// get argument value
*((int *) par) = 0;// clear argument value
va_end(par);
n = n > 1 ? n : 1;
#ifdef DEBUGMODE
printf("debug: action = %s, counter = %d, n = %d\n", action, cnt, n);
#endif
if (is_init(action))
init(&cnt);
else if (is_increment(action))
increment(&cnt, n);
else if (is_decrement(action))
decrement(&cnt, n);
else if (is_show(action))
show(&cnt);
else
printf("unsupported action\n");
}
int main() {
counter("init"); // counter = 0
counter("increment"); // counter = 1
counter("increment"); // counter = 2
counter("show"); // counter = 2
counter("increment", 5); // counter = 7
counter("show"); // counter = 7
counter("decrement"); // counter = 6
counter("show"); // counter = 6
counter("decrement", 3); // counter = 3
counter("show"); // counter = 3
counter("init"); // counter = 0
counter("show"); // counter = 0
counter("test"); // unsupported action
return 0;
}
Или так
#include <stdio.h>
#include <stdarg.h>
// actions
typedef enum {init, increment, decrement, show, test} actions;
// check requested init action
int is_init(actions action) {
return action == init;
}
// check requested increment action
int is_increment(actions action) {
return action == increment;
}
// check requested decrement action
int is_decrement(actions action) {
return action == decrement;
}
// check requested show action
int is_show(actions action) {
return action == show;
}
// init counter action
void init_action(int *cnt) {
*cnt = 0;
}
// increment counter action
void increment_action(int *cnt, int n) {
(*cnt) += n;
}
// decrement counter action
void decrement_action(int *cnt, int n) {
(*cnt) -= n;
}
// show counter action
void show_action(const int *cnt) {
printf("counter = %d\n", *cnt);
}
// counter encapsulation
void counter(actions action, ...) {
static int cnt = 0; // private
va_list par;
va_start(par, action);
int n = *((int *) par);// get argument value
*((int *) par) = 0;// clear argument value
va_end(par);
n = n > 1 ? n : 1;
#ifdef DEBUGMODE
printf("debug: action = %s, counter = %d, n = %d\n", action, cnt, n);
#endif
if (is_init(action))
init_action(&cnt);
else if (is_increment(action))
increment_action(&cnt, n);
else if (is_decrement(action))
decrement_action(&cnt, n);
else if (is_show(action))
show_action(&cnt);
else
printf("unsupported action\n");
}
int main() {
counter(init); // counter = 0
counter(increment); // counter = 1
counter(increment); // counter = 2
counter(show); // counter = 2
counter(increment, 5); // counter = 7
counter(show); // counter = 7
counter(decrement); // counter = 6
counter(show); // counter = 6
counter(decrement, 3); // counter = 3
counter(show); // counter = 3
counter(init); // counter = 0
counter(show); // counter = 0
counter(test); // unsupported action
return 0;
}
Subscribe to:
Posts
(
Atom
)