C/C++. Counting bits

Ниже приведены способы подсчета битов в беззнаковом целом числе. Все эти способы помещены в пространстве имен utils. По быстроте данные способы располагаются в следующем порядке (по возрастанию):

utils::count_bits < utils::count_bits2 < utils::count_bits3 <= utils::count_bits4

В следующей ссылке предлагается более подробное описание данной темы - "Обстоятельно о подсчете единичных битов".
Всем удачи!   

#include <iostream>
#include <bitset>

/* support bits count */
class Bits_Counter {
    static unsigned char byte_bit_count[256]; /* lookup table */
public:
    // must be called before the first call
    // to the count method
    void initialize() {
        int cnt, n;

        for (int i = 0; i < 256; i++) {
            cnt = 0;
            n = i;

            while (n != 0) {
                n = n & (n - 1);
                cnt++;
            }

            byte_bit_count[i] = cnt;
        }
    }

    int count(unsigned int n) {
        const unsigned char * byte = (unsigned char *) &n;

        return byte_bit_count[byte[0]] + byte_bit_count[byte[1]] +
               byte_bit_count[byte[2]] + byte_bit_count[byte[3]];
    }
};

unsigned char Bits_Counter::byte_bit_count[256];

/* utilities for count bits in given number */
namespace utils {
    using namespace std;

    // show bits
    void show_bits(unsigned int n) {
        string binary;

        while (n != 0) {
            binary = bitset<8>(n).to_string();
            cout << binary << endl;
            n = n >> 1;
        }
    }

    // count bits
    int count_bits(unsigned int n) {
        int cnt = 0;

        while (n != 0) {
            if (n & 1) cnt++;
            n = n >> 1;
        }

        return cnt;
    }

    // count bits
    int count_bits2(unsigned int n) {
        int cnt = 0;

        while (n != 0) {
            n = n & (n - 1);
            cnt++;
        }

        return cnt;
    }

    // count bits
    int count_bits3(unsigned int n) {
        Bits_Counter bits_counter;
        bits_counter.initialize();
        return bits_counter.count(n);
    }

    // count bits
    int count_bits4(unsigned int n) {
        static unsigned int mask[] = { 0x55555555,
                                                           0x33333333,
                                                           0x0F0F0F0F,
                                                           0x00FF00FF,
                                                           0x0000FFFF };

        for (int i = 0, shift = 1; i < 5; i++, shift *= 2) {
            n = (n & mask[i]) + ((n >> shift) & mask[i]);
        }

        return n;
    }
};

int main()
{
    unsigned int n = 55689; // 1010111000001

    std::cout << utils::count_bits(n)  << std::endl  // 8
              << utils::count_bits2(n) << std::endl       // 8
              << utils::count_bits3(n) << std::endl       // 8
              << utils::count_bits4(n);                           // 8

    return 0;
}

Oracle. Compile all of the invalid objects in your schema

For compile all of the invalid objects owned by YOUR_SCHEMA (note: must use upper case on the schema name):

begin
  dbms_utility.compile_schema('YOUR_SCHEMA');
end;

If some objects are still invalid that means there is some error with them.

Oracle. ANSI join syntax limitation in materialized views.

Начиная с версии 9 в Oracle для объединений таблиц стал доступен ANSI sql-синтаксиc (стандарт SQL:1999):

INNER JOIN
NATURAL JOIN
CROSS JOIN
LEFT OUTER JOIN
RIGHT OUTER JOIN
FULL OUTER JOIN

Данный синтаксис для современного разработчика более естественен, по сравнению с "old-style". Так же данный синтаксис расширяет возможности объединения таблиц (например, возможность полного объединения с использованием FULL OUTER JOIN). Но тем не менее получается, что полностью от старого синтаксиса невозможно отказаться, если Вам необходимо использовать в своих решениях материализованные представления (MATERIALIZED VIEWS) в режиме ON COMMIT. Связано это с тем, что при создании представления невозможно использовать объединения "ANSI-style".

Напоследок напомню про один нюанс использования объединений старого стиля: использовать метку (+) необходимо непосредственно с полем объединения, например:

select t1.*, t2.*
from table1 t1, table2 t2
/* where regexp_substr(t1.field, '\d+') = regexp_substr(t2.field, '\d+') (+) */
where regexp_substr(t1.field, '\d+') = regexp_substr(t2.field (+), '\d+')

В примере ошибочный вариант использования (+) закомментирован.
Или такой пример:

select t1.*, t2.*
from table1 t1, table2 t2 
where t1.id = t2.id (+)
    and regexp_like(t2.field (+), '^[A-Za-z]+')

Всем удачи :)

C++11. Recursion in lambda expression

Ниже представлен пример использования рекурсии с использованием лямбда-выражения

#include <iostream>
#include <functional>

// recursive print function
std::function<void (const std::string&, int)> print = [&] (const std::string& str, int times) {
    std::cout << str;
    if (times > 1) print(str, times - 1);
};

int main() {
   
    print("!", 5); // !!!!!

    return 0;
}


В данном примере в лямбда-выражении в списке захвата задан неявный захват по ссылке без которого Вы получите ошибку времени компиляции. Если Вам необходимо ограничить область захвата, тогда можно уточнить сие в списке захвата:

std::function<void (const std::string&, int)> print = [&print] (const std::string& str, int times) {
    std::cout << str << std::endl;
    if (times > 1) print(str, times - 1);
};


Где этим можно воспользоваться, ведь намного эффективней явно определить такого рода рекурсивную функцию:

void print(const std::string& str, int n = 1) {
    std::cout << str;
    if (n > 1) print(str, n - 1);
};


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

#include <iostream>
#include <vector>
#include <functional>

namespace util {
    using namespace std;

    void selection_sort(vector<int>& vec, int len);

    void insertion_sort(vector<int>& vec, int len);

    void bubble_sort(vector<int>& vec, int len);

    void quick_sort(vector<int>& vec, int len) {
        std::function<void (vector<int>&, int, int)> sorter = [&] (vector<int>& vec, int l, int r) {
            int x = vec[l + (r - l) / 2];
            int i = l;
            int j = r;

            while(i <= j) {
                while(vec[i] < x) i++;
                while(vec[j] > x) j--;

                if (i <= j) {
                    swap(vec[i], vec[j]);
                    i++;
                    j--;
                }
            }

            if (i < r) sorter(vec, i, r);
            if (l < j) sorter(vec, l, j);
        };

        sorter(vec, 0, len - 1);
    }
}


int main() {

    std::vector<int> numbers = {10, 1, 9, 2, 8, 3, 7, 4, 6, 5};
    util::quick_sort(numbers, numbers.size()); // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10

    return 0;
}

PLSQL. Bitwise operations

В plsql отсутствует нативная поддержка побитовых операций, кроме одной - bitand. При необходимости данную возможность можно реализовать самостоятельно. Ниже приведен пример реализации побитового OR и побитового XOR:

-- bit or
function bitor(x number, y number) return number
is
begin
  return (x + y) - bitand(x, y);
end;

-- bit xor
function bitxor(x number, y number) return number
is
begin
  return (x + y) - bitand(x, y) * 2;
end;


Для реализации операций побитовых сдвигов можно воспользоваться следующим подходом:

declare
  -- convert binary to decimal
  function bin2dec(binval in varchar2) return number
  is
    l_digits number;
    l_curr_digit char(1);
    l_curr_digit_dec number;
    l_result number := 0;
  begin
    l_digits := length(binval);
   
    for i in 1..l_digits loop
       l_curr_digit := substr(binval, i, 1);
       l_curr_digit_dec := to_number(l_curr_digit);
       l_result := (l_result * 2) + l_curr_digit_dec;
    end loop;
   
    return l_result;
  end;
  
  -- convert decimal to binary
  function dec2bin(p_num number) return varchar2
  is
    binval varchar2(64);
    l_num number := p_num;
  begin
    while (l_num > 0) loop
       binval := mod(l_num, 2) || binval;
       l_num := trunc(l_num / 2);
    end loop;   
    return binval;
  end;
 
  -- bitwise >> for binary
  function bin_shift_right(p_bin in varchar2, p_shift in number default null) return varchar2
  is
    l_length number;
    l_shift number;
  begin
    l_length := length(p_bin);
    l_shift := nvl(p_shift, 1);
     
    if (l_length <= 0) then
      return null;
    end if;
     
    if (l_shift > l_length) then
      l_shift := l_length;
    end if;

    return lpad(substr(p_bin, 1, l_length - l_shift), l_length, '0');
  end;

  -- bitwise >> for decimal
  function shift_right(p_num in number, p_shift in number default null) return number
  is
  begin
      if (trunc(p_num) <> p_num or p_num < 0) then
        raise program_error;
      end if;
     
    return nvl(bin2dec(bin_shift_right(dec2bin(p_num), p_shift)), 0);
  end;
 

begin
  dbms_output.put_line(bin2dec('1000')); -- 8
  dbms_output.put_line(shift_right(8, 1)); -- 4
  dbms_output.put_line(dec2bin(shift_right(8, 1))); -- 100
end;


Ниже приведен пример использования побитовых операций для контроля возникающих в приложении ошибок:

declare
  -- errors bit
  ERROR_FIRST constant integer := 1;      -- 0001
  ERROR_SECOND constant integer := 2; -- 0010
  ERROR_THIRD constant integer := 4;     -- 0100
  ERROR_FOURTH constant integer := 8; -- 1000
 
  -- for capturing errors
  l_errors number := 0;

  -- bit or
  function bitor(x number, y number) return number
  is
  begin
    return (x + y) - bitand(x, y);
  end;

  -- bit xor
  function bitxor(x number, y number) return number
  is
  begin
    return (x + y) - bitand(x, y) * 2;
  end;
  
  -- set error bit
  procedure set_error(p_errors in out number, p_error number)
  is
  begin
    p_errors := bitor(p_errors, p_error);
  end;
 
  -- check if given error captured
  function check_error(p_errors in number, p_error number) return boolean
  is
  begin
    return bitand(p_errors, p_error) = p_error;
  end;
 
  -- print all captured errors
  procedure print_errors(p_errors in number)
  is
    l_err varchar2(4000) := 'Catched errors:';
  begin
    if (check_error(p_errors, ERROR_FIRST)) then
      l_err := l_err || ' ERROR_FIRST,';
    end if;
   
    if (check_error(p_errors, ERROR_SECOND)) then
      l_err := l_err || ' ERROR_SECOND,';
    end if;
   
    if (check_error(p_errors, ERROR_THIRD)) then
      l_err := l_err || ' ERROR_THIRD,';
    end if;
   
    if (check_error(p_errors, ERROR_FOURTH)) then
      l_err := l_err || ' ERROR_FOURTH,';
    end if;
 
    dbms_output.put_line(l_err);
  end;
begin
  set_error(l_errors, ERROR_FIRST);
  set_error(l_errors, ERROR_FOURTH);
 
  print_errors(l_errors);
end;

C++. Empty base optimization (EBO, ECBO)

Рассмотрим элиминацию (оптимизацию) пустого базового класса на примере двух классов Foo и Bar:

class Foo {};

class Bar {
    Foo f;
    int i;
};


Класс Foo является пустым. Как известно, размер любого объекта пустого класса как - минимум - равен 1 байту (для большинства компиляторов):

sizeof(Foo) == 1 

Это достигается молчаливой вставкой компилятором одного байта (char) в такой пустой объект. Теперь посмотрим на размер класса Bar:

sizeof(Bar) == 2 * sizeof(int)

В данном случае объект класса Foo занимает 1 байт с выравниванием до размера члена i sizeof(int). Это связано с тем, что два базовых подобъекта одного типа должны иметь разные адреса.

Теперь организуем класс Bar с помощью наследования следующим образом:

class Bar : public Foo {
    int i;
};


И снова посмотрим на размер класса Bar:


sizeof(Bar) == sizeof(int)

В итоге мы видим, что компилятор при таком раскладе под подобъект Foo выделил 0 байт. В этом и состоит идея оптимизации пустого базового класса. В стандарте по этому поводу сказано:

A class with an empty sequence of [data] members and base class objects is an empty class. Complete objects and member subobjects of an empty class type shall have nonzero size.

Что мы и видим на деле. Всем успехов.

C++. Override and overload

Ниже рассмотрены случаи перекрытия (override) и перегрузки (overload) на примере двух классов Account и Deposit:

class Account {
        // ...
        void display(const char *fmt);
        void display(const int mode = 0);
};

class Deposit : public Account {
        // ...
        void display(const std::string &fmt);
};

В данном случае одноименный метод display в производном классе Deposit
перекрывает (override) методы базового класса Account, таким образом
методы базового и производного классов не образуют множество перегруженных
функций.

Использование в производном классе объявления using вводит именованный
член базового класса в область видимости производного, тем самым перегружая (overload)
одноименный метод display позволяя создать единое множество перегруженных функций базового и производного классов.

class Account {
        // ...
        void display(const char *fmt);
        void display(const int mode = 0);
};

class Deposit : public Account {
// ...
void display(const std::string &fmt);
using Account::display;
};

В виде примечания в Java понятие перекрытия существует только если у одноименных методов идентичны их сигнатуры, в остальном все методы перегружаются создавая единое множество перегруженных методов базового и производного классов:

class Account {
public void display(char fmt) {
// ...
}

public void display(int mode) {
// ...
}
}

class Deposit extends Account {

public void display(String fmt) {
// ...
}

// ...
}

Также стоит упомянуть о новом синтаксисе C++11 - использование спецификатора override. Использование данного спецификатора гарантирует, что функция 1) - является виртуальной и 2) перекрывает виртуальную функцию базового класса с идентичной ей сигнатурой:

class Alpha {
public:
    virtual void foo();
    void bar(); 
};

class Beta : public Alpha {
public:    
    void foo() override;               // допустимо
    // void foo() const override;   // недопустимо
    // void bar() override;            // недопустимо
};

C++. Qt. Forward declaration. One way to get access to the parent form from a child form

При работе с Qt встала задача: как правильно организовать доступ к данным родительской формы из дочерней формы. Был выбран вариант передачи указателя на экземпляр данной формы в конструктор дочерней формы. В этом случае у Вас может возникнуть следующая проблема. Для родительской формы вы подключаете заголовочный файл определения класса дочерней формы. Но и дочернему классу нужно сообщить о классе (типе) родительской формы. Если подключить заголовочный файл определения класса родительской формы, то возникнет ситуация циклического подключения этих заголовочных файлов. Чтобы этого избежать, необходимо воспользоваться техникой "опережающего определения" (forward declaration):

bar.h

#include "foo.h"

class bar {
public:
    bar();
};

bar.cpp

bar::bar() {
    foo f ();
    // work with object f
}

foo.h

class bar; // forward declaration

class foo {
public:
    foo(bar* obj); // pointer or a reference
};

foo.cpp

#include "bar.h"
#include "foo.h"

foo::foo(bar* obj) {
    // work with pointer obj
}

Ниже приведен пример данного подхода, в котором дочерняя форма при отрисовке таблицы со списком элементов обращается к соответствующему списку родительской формы.

item.h

#ifndef ITEM
#define ITEM

#include <QString>

class Item {
private:
    int id;
    QString description;

public:
    Item(int id, QString description) : id(id), description(description) {}

    void setId(int id) {
        this->id = id;
    }

    int getId() const {
        return id;
    }

    void setDescription(QString description) {
        this->description = description;
    }

    QString getDescription() const {
        return description;
    }
};

#endif

mainwindow.h

#ifndef MAINWINDOW
#define MAINWINDOW

#include <QMainWindow>
#include "itemswindow.h"
#include "item.h"

class MainWindow : public QMainWindow {
Q_OBJECT

public:
    MainWindow(QWidget* wgt = 0);
    QList<Item> itemList;

public slots:
    void slotItems();
};

#endif

mainwindow.cpp

#include <QtWidgets>
#include "mainwindow.h"

MainWindow::MainWindow(QWidget* wgt) : QMainWindow(wgt) {
    QMenu* menu = new QMenu("Menu");
    menu->addAction("Exit", qApp, SLOT(quit()));
    menuBar()->addMenu(menu);

    // central widget
    QWidget* centralWidget = new QWidget;

    QVBoxLayout* buttonsWidgetLayout = new QVBoxLayout(centralWidget);
    buttonsWidgetLayout->setAlignment(Qt::AlignTop | Qt::AlignLeft);

    QPushButton* itemsBttn = new QPushButton("Items");
    itemsBttn->setFixedWidth(150);
    buttonsWidgetLayout->addWidget(itemsBttn);

    connect(itemsBttn, SIGNAL(clicked()), SLOT(slotItems()));

    setCentralWidget(centralWidget);
    setWindowTitle("MainWindow");

    // for testing
    itemList.append(Item(1, "First item"));
    itemList.append(Item(2, "Second item"));
    itemList.append(Item(3, "Third item"));
    itemList.append(Item(4, "Fourth item"));
    itemList.append(Item(5, "Fifth item"));
}

void MainWindow::slotItems() {
    ItemsWindow* itemsWindow = new ItemsWindow(this, this);
    itemsWindow->exec();
    delete itemsWindow;
}

itemswindow.h

#ifndef ITEMSWINDOW
#define ITEMSWINDOW

#include <QtWidgets>
#include <item.h>

class MainWindow;

class ItemsWindow : public QDialog {
Q_OBJECT

private:
    QTableWidget* table;

public:
    ItemsWindow(MainWindow* mw = 0, QWidget* wgt = 0);
};

#endif

itemswindow.cpp

#include "mainwindow.h"
#include "itemswindow.h"

ItemsWindow::ItemsWindow(MainWindow* mw, QWidget* wgt) :
    QDialog(wgt, Qt::WindowTitleHint | Qt::WindowCloseButtonHint) {

    QVBoxLayout* verticalLayout = new QVBoxLayout;
    QHBoxLayout* horizontalBottomLayout = new QHBoxLayout;

    QPushButton* okBttn = new QPushButton("&OK");
    okBttn->setFixedWidth(60);

    connect(okBttn, SIGNAL(clicked()), SLOT(accept()));
    
horizontalBottomLayout->setAlignment(Qt::AlignRight);
horizontalBottomLayout->addWidget(okBttn);

    table = new QTableWidget();
    table->setColumnCount(2);

    QStringList list;
    list << "Id" << "Description";
    table->setHorizontalHeaderLabels(list);
table->setEditTriggers(QAbstractItemView::NoEditTriggers);

    if (mw != NULL && !mw->itemList.empty()) {
        int itemsCnt = mw->itemList.count();
        table->setRowCount(itemsCnt);

        QTableWidgetItem* tableItem = 0;
        for (int i = 0; i < itemsCnt; i++) {
            Item item = mw->itemList.at(i);

            tableItem = new QTableWidgetItem(QString::number(item.getId()));
            tableItem->setTextAlignment(Qt::AlignCenter);
            table->setItem(i, 0, tableItem);

            tableItem = new QTableWidgetItem(item.getDescription());
            table->setItem(i, 1, tableItem);
        }
    }

    this->setWindowTitle("Items");
    verticalLayout->addWidget(table);
    verticalLayout->addLayout(horizontalBottomLayout);
    setLayout(verticalLayout);
}

main.cpp

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char** argv) {
    QApplication app(argc, argv);

    MainWindow window;
    window.show();

    return app.exec();
}

Исходники доступны по данной ссылке - source.

C++. Qt5.6. Combobox with checkboxes

На днях работал с замечательной библиотекой Qt. Нужно было добавить возможность выбора элементов по флажкам в выпадающем списке. Вроде тривиальная gui задача, но у меня немного вызвало затруднение. Ниже приведено мое решение. Исходная платформа - Win64.


multilist.h

#ifndef MULTILIST
#define MULTILIST

#include <QtWidgets>

class MultiList : public QComboBox {
    Q_OBJECT

private:
    QString displayText;
    QStandardItemModel *model;

public:
    MultiList(QWidget *parent = 0) : QComboBox(parent) {
        setEditable(true);

        displayText = "";
        model = new QStandardItemModel;
        slotUpdateText();

        connect(model, SIGNAL(itemChanged(QStandardItem*)), this, SLOT(slotUpdate()));
    }

    void addItem(const QString &text) {
        int row = model->rowCount();
        QStandardItem* item = new QStandardItem();
        item->setText(text);
        item->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
        item->setData(Qt::Unchecked, Qt::CheckStateRole);
        model->setItem(row, 0, item);
        this->setModel(model);
    }

    void addItems(const QStringList &texts) {
        for (int i = 0; i < texts.count(); i++) {
            addItem(texts.at(i));
        }
    }

    QStringList getCheckedItems() const {
        QStringList checkedItems;

        for (int i = 0; i < model->rowCount(); i++) {
            if (model->item(i, 0)->checkState() == Qt::Checked) {
                checkedItems << model->item(i, 0)->text();
            }
        }

        return checkedItems;
    }

    void setCheckedItems(const QStringList &items) {
        for (int i = 0; i < items.count(); i++) {
            int index = findText(items.at(i));

            if (index != -1) {
                model->item(index)->setData(Qt::Checked, Qt::CheckStateRole);
            }
        }

        slotUpdate();
    }

public slots:
    void slotUpdateText() {
        lineEdit()->setText(displayText);
    }

    void slotUpdate() {
        displayText = "";

        for (int i = 0; i < model->rowCount(); i++) {
            if (model->item(i, 0)->checkState() == Qt::Checked) {
                displayText = displayText + model->item(i, 0)->text() + "; ";
            }
        }

        QTimer::singleShot(0, this, SLOT(slotUpdateText()));
    }
};


#endif

main.cpp

#include "multilist.h"

int main(int argc, char** argv) {
    QApplication app(argc, argv);

    MultiList *multiList = new MultiList();

    multiList->addItems(QStringList() << "One" << "Two" << "Three" << "Four");
    multiList->setCheckedItems(QStringList() << "One" << "Two");

    QHBoxLayout *layout = new QHBoxLayout();

    layout->addWidget(new QLabel("Select items:"));
    layout->addWidget(multiList, 1);

    QWidget widget;
    widget.setWindowTitle("MultiList example");
    widget.setLayout(layout);
    widget.show();

    return app.exec();

}

PLSQL. UTL_HTTP package. Sending cyrillic chars

Если Вы используете встроенный пакет utl_http, то возможно Вы сталкивались с проблемой кодировок при отправке текстовых данных на кириллице. Для решения данной проблемы необходимо воспользоваться методов escape встроенного пакета utl_url:

utl_url.escape('Привет, мир!', true, 'utf-8')

Данный метод возвращает строку, готовую к отправке. Ниже приведен пример:

declare
  req utl_http.req;
  res utl_http.resp;
  url varchar2(4000) := 'http://some_address:port?test=1';
  l_data varchar2(100);
begin
  l_data := 'Привет, мир!';

  l_data := utl_url.escape(l_data, true, 'utf-8');

  utl_http.set_response_error_check(false);
  req := utl_http.begin_request(url, 'POST', 'HTTP/1.1');
 
  /* if need proxy connection
  utl_http.set_proxy('company.proxy.com:port', '');
  utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
  */
 
  utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
  utl_http.set_header(req, 'Content-Length', length(l_data));
  utl_http.set_header(req, 'Content-Encoding', 'UTF-8');

  -- send post data
  utl_http.write_text(req, l_data);
  res := utl_http.get_response(req);
  utl_http.end_response(res);

  /* if need check status code
  res.status_code
  */

  exception
    when utl_http.end_of_body then
      utl_http.end_response(res);
    when others then
      dbms_output.put_line(sqlerrm);
end;

PLSQL. UTL_HTTP package

Ниже приведены примеры использования встроенного пакета utl_http. Например, если Вам необходимо запросить некоторые данные по веб адресу, тогда можно воспользоваться пакетом utl_http следующим образом: 

declare
  req utl_http.req;
  res utl_http.resp;
  url varchar2(4000) := 'http://aviationweather.gov/adds/tafs/';
  param varchar2(200) := '?station_ids=vhhh' || '&' || 'std_trans=standart' || '&' || 'submit_both=Get+TAFs+and+METARs';
  l_data varchar2(32000);
begin
  dbms_output.enable(1000000000);
 
  utl_http.set_response_error_check(false);
  req := utl_http.begin_request(url || param); -- GET
    

  /* if need proxy
  utl_http.set_proxy('company.proxy.com:port', '');
  utl_http.set_authentication(req, 'user', 'password', for_proxy => true);

  */
   
  utl_http.set_header(req, 'User-Agent', 'Mozilla/4.0');
   
  res := utl_http.get_response(req);
   
  loop
    utl_http.read_line(res, l_data, true);
    dbms_output.put_line(l_data);
  end loop;
   
  utl_http.end_response(res);

  exception
    when utl_http.end_of_body then
      utl_http.end_response(res);
    when others then
      dbms_output.put_line(sqlerrm);
end;


В данном случае в запросе используется GET метод, если Вам необходимо использовать POST запросы, тогда можно использовать данный пакет следующим образом:

declare
  req utl_http.req;
  res utl_http.resp;
  url varchar2(4000) := 'http://some_address:port?test=1';
  l_data varchar2(32767);
begin
  l_data := 'bla-bla-bla';

  utl_http.set_response_error_check(false);
  req := utl_http.begin_request(url, 'POST', 'HTTP/1.1');
 
  /* if need proxy connection
  utl_http.set_proxy('company.proxy.com:port', '');
  utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
  */
 
  utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
  utl_http.set_header(req, 'Content-Length', length(l_data));
  utl_http.set_header(req, 'Content-Encoding', 'UTF-8');

  -- send post data
  utl_http.write_text(req, l_data);
  res := utl_http.get_response(req);
  utl_http.end_response(res);

  /* if need check status code
  res.status_code
  */

  exception
    when utl_http.end_of_body then
      utl_http.end_response(res);
    when others then
      dbms_output.put_line(sqlerrm);
end;


Ниже приведен еще один пример POST запроса, но в примере рассмотрена возможность возврата полученного ответа в виде данных типа CLOB:

create or replace package body test_pkg is

  procedure send_message(p_message in varchar2,
                         p_status out integer,
                         p_response out clob)
    is
      req utl_http.req;
      res utl_http.resp;
      url varchar2(4000) := 'http://some_address:port?test=1';
      buffer varchar2(4000);
      clob_buffer clob;
    begin
      utl_http.set_response_error_check(false);
      req := utl_http.begin_request(url, 'POST', ' HTTP/1.1');
     
      /* if need proxy connection
      utl_http.set_proxy('company.proxy.com:port', '');
      utl_http.set_authentication(req, 'user', 'password', for_proxy => true);
      */
     
      utl_http.set_header(req, 'Content-Type', 'charset=UTF-8');
      utl_http.set_header(req, 'Content-Length', length(p_message));
      utl_http.set_header(req, 'Content-Encoding', 'UTF-8');

      -- send post data
      utl_http.write_text(req, p_message);
      res := utl_http.get_response(req);

      -- set response status
      if res.status_code = 200 then
        p_status := 1;
      else
        p_status := 0;
      end if;

      -- read response
      begin
        clob_buffer := empty_clob;

        loop
          utl_http.read_text(res, buffer, length(buffer));
          clob_buffer := clob_buffer || buffer;
        end loop;

        p_response := clob_buffer;
        utl_http.end_response(res);

        exception
          when utl_http.end_of_body then
            p_response := clob_buffer;
            utl_http.end_response(res);
          when others then null;
            dbms_output.put_line(sqlerrm);
            dbms_output.put_line(dbms_utility.format_error_backtrace);
            utl_http.end_response(res);
      end;

      exception
        when others then
          dbms_output.put_line(sqlerrm);
    end;
 
begin
  -- init
  null;
end test_pkg;

Oracle. Linear Regression

Довольно-таки распространенной статистической задачей анализа ряда данных является поиск линейной регрессии. Oracle предоставляет для данной цели ряд функций. Ниже приведен пример нахождения коэффициентов линейной регрессии y = kx + b:

with
  src(y, x) as (
    select 3, 0 from dual union all
    select 5, 1 from dual union all
    select 7, 2 from dual union all
    select 9, 3 from dual union all
    select 11, 4 from dual union all
    select 13, 5 from dual
  )

select 
  regr_slope(y, x) as k, 
  regr_intercept(y, x) as b 
from src

На выходе получим вот такую зависимость:

y = 2x + 3

Вообще коэффициенты линейной регрессии можно найти и аналитически с помощью метода наименьших квадратов по следующим уравнениям:

Nginx with Apache. 504 Gateway time-out

В моем случае Nginx работает в связке с Apache в роли проксирующего веб-сервера. Попробовали выполнить тяжелый скрипт и получили вот такой ответ:

504 Gateway time-out

На стороне Apache ограничений нет. Как выяснилось время ожидания при чтении ответа и время ожидания при передаче запроса у Nginx по умолчанию выставлено в одну минуту. Поэтому для решения данной проблемы достаточно прописать в конфиге (например в location) следующие строки:

server {
...
  location / {
    ...
    proxy_read_timeout 600; # время ожидания при чтении ответа
    proxy_send_timeout 600; # время ожидания при передаче запроса
    ...
  }
...
}

После перегружаем настройку Nginx

sudo nginx -s reload