UNPKG

limber-firebird-client

Version:

Cliente JavaScript/Typescrypt para Node.js de acesso a banco de dados Firebird charset ISO8859_1 e UTF8

1,684 lines (1,405 loc) 179 kB
const net = require('net'), os = require('os'), path = require('path'), Events = require('events'), Stream = require('stream'), messages = require('./messages.js'), crypt = require('./unix-crypt.js'), serialize = require('./serialize.js'), errors = require('./errors.js'), XdrReader = serialize.XdrReader, BlrReader = serialize.BlrReader, XdrWriter = serialize.XdrWriter, BlrWriter = serialize.BlrWriter, BitSet = serialize.BitSet, GDSError = errors.GDSError; /** * Parse date from string * @return {Date} */ if (String.prototype.parseDate === undefined) { String.prototype.parseDate = function () { var self = this.trim(); var arr = self.indexOf(' ') === -1 ? self.split('T') : self.split(' '); var index = arr[0].indexOf(':'); var length = arr[0].length; if (index !== -1) { var tmp = arr[1]; arr[1] = arr[0]; arr[0] = tmp; } if (arr[0] === undefined) { arr[0] = ''; } var noTime = arr[1] === undefined ? true : arr[1].length === 0; for (var i = 0; i < length; i++) { var c = arr[0].charCodeAt(i); if (c > 47 && c < 58) { continue; } if (c === 45 || c === 46) { continue; } if (noTime) { return new Date(self); } } if (arr[1] === undefined) { arr[1] = '00:00:00'; } var firstDay = arr[0].indexOf('-') === -1; var date = (arr[0] || '').split(firstDay ? '.' : '-'); var time = (arr[1] || '').split(':'); var parsed = []; if (date.length < 4 && time.length < 2) { return new Date(self); } index = (time[2] || '').indexOf('.'); // milliseconds if (index !== -1) { time[3] = time[2].substring(index + 1); time[2] = time[2].substring(0, index); } else { time[3] = '0'; } parsed.push(parseInt(date[firstDay ? 2 : 0], 10)); // year parsed.push(parseInt(date[1], 10)); // month parsed.push(parseInt(date[firstDay ? 0 : 2], 10)); // day parsed.push(parseInt(time[0], 10)); // hours parsed.push(parseInt(time[1], 10)); // minutes parsed.push(parseInt(time[2], 10)); // seconds parsed.push(parseInt(time[3], 10)); // miliseconds var def = new Date(); for (i = 0, length = parsed.length; i < length; i++) { if (isNaN(parsed[i])) { parsed[i] = 0; } var value = parsed[i]; if (value !== 0) { continue; } switch (i) { case 0: if (value <= 0) { parsed[i] = def.getFullYear(); } break; case 1: if (value <= 0) { parsed[i] = def.getMonth() + 1; } break; case 2: if (value <= 0) { parsed[i] = def.getDate(); } break; } } return new Date(parsed[0], parsed[1] - 1, parsed[2], parsed[3], parsed[4], parsed[5]); }; } function noop() { } const MAX_BUFFER_SIZE = 8192; const op_void = 0, // Packet has been voided op_connect = 1, // Connect to remote server op_exit = 2, // Remote end has exitted op_accept = 3, // Server accepts connection op_reject = 4, // Server rejects connection op_disconnect = 6, // Connect is going away op_response = 9, // Generic response block // Full context server operations op_attach = 19, // Attach database op_create = 20, // Create database op_detach = 21, // Detach database op_compile = 22, // Request based operations op_start = 23, op_start_and_send = 24, op_send = 25, op_receive = 26, op_unwind = 27, // apparently unused, see protocol.cpp's case op_unwind op_release = 28, op_transaction = 29, // Transaction operations op_commit = 30, op_rollback = 31, op_prepare = 32, op_reconnect = 33, op_create_blob = 34, // Blob operations op_open_blob = 35, op_get_segment = 36, op_put_segment = 37, op_cancel_blob = 38, op_close_blob = 39, op_info_database = 40, // Information services op_info_request = 41, op_info_transaction = 42, op_info_blob = 43, op_batch_segments = 44, // Put a bunch of blob segments op_que_events = 48, // Que event notification request op_cancel_events = 49, // Cancel event notification request op_commit_retaining = 50, // Commit retaining (what else) op_prepare2 = 51, // Message form of prepare op_event = 52, // Completed event request (asynchronous) op_connect_request = 53, // Request to establish connection op_aux_connect = 54, // Establish auxiliary connection op_ddl = 55, // DDL call op_open_blob2 = 56, op_create_blob2 = 57, op_get_slice = 58, op_put_slice = 59, op_slice = 60, // Successful response to op_get_slice op_seek_blob = 61, // Blob seek operation // DSQL operations op_allocate_statement = 62, // allocate a statment handle op_execute = 63, // execute a prepared statement op_exec_immediate = 64, // execute a statement op_fetch = 65, // fetch a record op_fetch_response = 66, // response for record fetch op_free_statement = 67, // free a statement op_prepare_statement = 68, // prepare a statement op_set_cursor = 69, // set a cursor name op_info_sql = 70, op_dummy = 71, // dummy packet to detect loss of client op_response_piggyback = 72, // response block for piggybacked messages op_start_and_receive = 73, op_start_send_and_receive = 74, op_exec_immediate2 = 75, // execute an immediate statement with msgs op_execute2 = 76, // execute a statement with msgs op_insert = 77, op_sql_response = 78, // response from execute, exec immed, insert op_transact = 79, op_transact_response = 80, op_drop_database = 81, op_service_attach = 82, op_service_detach = 83, op_service_info = 84, op_service_start = 85, op_rollback_retaining = 86, op_partial = 89, // packet is not complete - delay processing op_trusted_auth = 90, op_cancel = 91, op_cont_auth = 92, op_ping = 93, op_accept_data = 94, // Server accepts connection and returns some data to client op_abort_aux_connection = 95, // Async operation - stop waiting for async connection to arrive op_crypt = 96, op_crypt_key_callback = 97, op_cond_accept = 98; // Server accepts connection, returns some data to client // and asks client to continue authentication before attach call const CONNECT_VERSION2 = 2, CONNECT_VERSION3 = 3, ARCHITECTURE_GENERIC = 1; const // Protocol 10 includes support for warnings and removes the requirement for // encoding and decoding status codes PROTOCOL_VERSION10 = 10, // Since protocol 11 we must be separated from Borland Interbase. // Therefore always set highmost bit in protocol version to 1. // For unsigned protocol version this does not break version's compare. FB_PROTOCOL_FLAG = 0x8000, FB_PROTOCOL_MASK = ~FB_PROTOCOL_FLAG & 0xFFFF, // Protocol 11 has support for user authentication related // operations (op_update_account_info, op_authenticate_user and // op_trusted_auth). When specific operation is not supported, // we say "sorry". PROTOCOL_VERSION11 = (FB_PROTOCOL_FLAG | 11), // Protocol 12 has support for asynchronous call op_cancel. // Currently implemented asynchronously only for TCP/IP. PROTOCOL_VERSION12 = (FB_PROTOCOL_FLAG | 12), // Protocol 13 has support for authentication plugins (op_cont_auth). PROTOCOL_VERSION13 = (FB_PROTOCOL_FLAG | 13), PROTOCOL_VERSION15 = (FB_PROTOCOL_FLAG | 15), PROTOCOL_VERSION16 = (FB_PROTOCOL_FLAG | 16); const CNCT_user = 1, // User name CNCT_passwd = 2, // CNCT_ppo = 3, // Apollo person, project, organization. OBSOLETE. CNCT_host = 4, CNCT_group = 5, // Effective Unix group id CNCT_user_verification = 6, // Attach/create using this connection will use user verification CNCT_specific_data = 7, // Some data, needed for user verification on server CNCT_plugin_name = 8, // Name of plugin, which generated that data CNCT_login = 9, // Same data as isc_dpb_user_name CNCT_plugin_list = 10, // List of plugins, available on client CNCT_client_crypt = 11, // Client encyption level (DISABLED/ENABLED/REQUIRED) WIRE_CRYPT_DISABLED = 0, WIRE_CRYPT_ENABLED = 1, WIRE_CRYPT_REQUIRED = 2; const DSQL_close = 1, DSQL_drop = 2, DSQL_unprepare = 4; // >= 2.5 // Protocols types (accept_type) const ptype_rpc = 2, // Simple remote procedure call ptype_batch_send = 3, // Batch sends, no asynchrony ptype_out_of_band = 4, // Batch sends w/ out of band notification ptype_lazy_send = 5, // Deferred packets delivery; ptype_mask = 0xFF, // Mask - up to 255 types of protocol pflag_compress = 0x100; // Turn on compression if possible const SUPPORTED_PROTOCOL = [ // [PROTOCOL_VERSION10, ARCHITECTURE_GENERIC, ptype_rpc, ptype_batch_send, 1], // [PROTOCOL_VERSION11, ARCHITECTURE_GENERIC, ptype_lazy_send, ptype_lazy_send, 2], [PROTOCOL_VERSION12, ARCHITECTURE_GENERIC, ptype_batch_send, ptype_batch_send, 3], [PROTOCOL_VERSION13, ARCHITECTURE_GENERIC, ptype_batch_send, ptype_batch_send, 4], [PROTOCOL_VERSION15, ARCHITECTURE_GENERIC, ptype_batch_send, ptype_batch_send, 5], [PROTOCOL_VERSION16, ARCHITECTURE_GENERIC, ptype_batch_send, ptype_batch_send, 6], ]; const SQL_TEXT = 452, // Array of char SQL_VARYING = 448, SQL_SHORT = 500, SQL_LONG = 496, SQL_FLOAT = 482, SQL_DOUBLE = 480, SQL_D_FLOAT = 530, SQL_TIMESTAMP = 510, SQL_BLOB = 520, SQL_ARRAY = 540, SQL_QUAD = 550, SQL_TYPE_TIME = 560, SQL_TYPE_DATE = 570, SQL_INT64 = 580, SQL_BOOLEAN = 32764, // >= 3.0 SQL_NULL = 32766, // >= 2.5 SQL_TIMESTAMP_TZ = 32754, // 4.0 SQL_TIME_TZ = 32756; // 4.0 /***********************/ /* ISC Services */ /***********************/ const isc_action_svc_backup = 1, /* Starts database backup process on the server */ isc_action_svc_restore = 2, /* Starts database restore process on the server */ isc_action_svc_repair = 3, /* Starts database repair process on the server */ isc_action_svc_add_user = 4, /* Adds a new user to the security database */ isc_action_svc_delete_user = 5, /* Deletes a user record from the security database */ isc_action_svc_modify_user = 6, /* Modifies a user record in the security database */ isc_action_svc_display_user = 7, /* Displays a user record from the security database */ isc_action_svc_properties = 8, /* Sets database properties */ isc_action_svc_add_license = 9, /* Adds a license to the license file */ isc_action_svc_remove_license = 10, /* Removes a license from the license file */ isc_action_svc_db_stats = 11, /* Retrieves database statistics */ isc_action_svc_get_ib_log = 12, /* Retrieves the InterBase log file from the server */ isc_action_svc_get_fb_log = isc_action_svc_get_ib_log, /* Retrieves the Firebird log file from the server */ isc_action_svc_nbak = 20, /* start nbackup */ isc_action_svc_nrest = 21, /* start nrestore */ isc_action_svc_trace_start = 22, isc_action_svc_trace_stop = 23, isc_action_svc_trace_suspend = 24, isc_action_svc_trace_resume = 25, isc_action_svc_trace_list = 26; const isc_info_svc_svr_db_info = 50, /* Retrieves the number of attachments and databases */ isc_info_svc_get_license = 51, /* Retrieves all license keys and IDs from the license file */ isc_info_svc_get_license_mask = 52, /* Retrieves a bitmask representing licensed options on the server */ isc_info_svc_get_config = 53, /* Retrieves the parameters and values for IB_CONFIG */ isc_info_svc_version = 54, /* Retrieves the version of the services manager */ isc_info_svc_server_version = 55, /* Retrieves the version of the InterBase server */ isc_info_svc_implementation = 56, /* Retrieves the implementation of the InterBase server */ isc_info_svc_capabilities = 57, /* Retrieves a bitmask representing the server's capabilities */ isc_info_svc_user_dbpath = 58, /* Retrieves the path to the security database in use by the server */ isc_info_svc_get_env = 59, /* Retrieves the setting of $INTERBASE */ isc_info_svc_get_env_lock = 60, /* Retrieves the setting of $INTERBASE_LCK */ isc_info_svc_get_env_msg = 61, /* Retrieves the setting of $INTERBASE_MSG */ isc_info_svc_line = 62, /* Retrieves 1 line of service output per call */ isc_info_svc_to_eof = 63, /* Retrieves as much of the server output as will fit in the supplied buffer */ isc_info_svc_timeout = 64, /* Sets / signifies a timeout value for reading service information */ isc_info_svc_get_licensed_users = 65, /* Retrieves the number of users licensed for accessing the server */ isc_info_svc_limbo_trans = 66, /* Retrieve the limbo transactions */ isc_info_svc_running = 67, /* Checks to see if a service is running on an attachment */ isc_info_svc_get_users = 68, /* Returns the user information from isc_action_svc_display_users */ isc_info_svc_stdin = 78; /* Services Properties */ const isc_spb_prp_page_buffers = 5, isc_spb_prp_sweep_interval = 6, isc_spb_prp_shutdown_db = 7, isc_spb_prp_deny_new_attachments = 9, isc_spb_prp_deny_new_transactions = 10, isc_spb_prp_reserve_space = 11, isc_spb_prp_write_mode = 12, isc_spb_prp_access_mode = 13, isc_spb_prp_set_sql_dialect = 14, isc_spb_num_att = 5, isc_spb_num_db = 6, // SHUTDOWN OPTION FOR 2.0 isc_spb_prp_force_shutdown = 41, isc_spb_prp_attachments_shutdown = 42, isc_spb_prp_transactions_shutdown = 43, isc_spb_prp_shutdown_mode = 44, isc_spb_prp_online_mode = 45, isc_spb_prp_sm_normal = 0, isc_spb_prp_sm_multi = 1, isc_spb_prp_sm_single = 2, isc_spb_prp_sm_full = 3, // WRITE_MODE_PARAMETERS isc_spb_prp_wm_async = 37, isc_spb_prp_wm_sync = 38, // ACCESS_MODE_PARAMETERS isc_spb_prp_am_readonly = 39, isc_spb_prp_am_readwrite = 40, // RESERVE_SPACE_PARAMETERS isc_spb_prp_res_use_full = 35, isc_spb_prp_res = 36, // Option Flags isc_spb_prp_activate = 0x0100, isc_spb_prp_db_online = 0x0200; // SHUTDOWN MODE /* · Backup Service ·*/ const isc_spb_bkp_file = 5, isc_spb_bkp_factor = 6, isc_spb_bkp_length = 7, isc_spb_bkp_ignore_checksums = 0x01, isc_spb_bkp_ignore_limbo = 0x02, isc_spb_bkp_metadata_only = 0x04, isc_spb_bkp_no_garbage_collect = 0x08, isc_spb_bkp_old_descriptions = 0x10, isc_spb_bkp_non_transportable = 0x20, isc_spb_bkp_convert = 0x40, isc_spb_bkp_expand = 0x80, isc_spb_bkp_no_triggers = 0x8000, // nbackup isc_spb_nbk_level = 5, isc_spb_nbk_file = 6, isc_spb_nbk_direct = 7, isc_spb_nbk_no_triggers = 0x01; /* Restore Service ·*/ const isc_spb_res_buffers = 9, isc_spb_res_page_size = 10, isc_spb_res_length = 11, isc_spb_res_access_mode = 12, isc_spb_res_fix_fss_data = 13, isc_spb_res_fix_fss_metadata = 14, isc_spb_res_am_readonly = isc_spb_prp_am_readonly, isc_spb_res_am_readwrite = isc_spb_prp_am_readwrite, isc_spb_res_deactivate_idx = 0x0100, isc_spb_res_no_shadow = 0x0200, isc_spb_res_no_validity = 0x0400, isc_spb_res_one_at_a_time = 0x0800, isc_spb_res_replace = 0x1000, isc_spb_res_create = 0x2000, isc_spb_res_use_all_space = 0x4000; /* · Repair Service ·*/ const isc_spb_rpr_commit_trans = 15, isc_spb_rpr_rollback_trans = 34, isc_spb_rpr_recover_two_phase = 17, isc_spb_tra_id = 18, isc_spb_single_tra_id = 19, isc_spb_multi_tra_id = 20, isc_spb_tra_state = 21, isc_spb_tra_state_limbo = 22, isc_spb_tra_state_commit = 23, isc_spb_tra_state_rollback = 24, isc_spb_tra_state_unknown = 25, isc_spb_tra_host_site = 26, isc_spb_tra_remote_site = 27, isc_spb_tra_db_path = 28, isc_spb_tra_advise = 29, isc_spb_tra_advise_commit = 30, isc_spb_tra_advise_rollback = 31, isc_spb_tra_advise_unknown = 33, isc_spb_rpr_validate_db = 0x01, isc_spb_rpr_sweep_db = 0x02, isc_spb_rpr_mend_db = 0x04, isc_spb_rpr_list_limbo_trans = 0x08, isc_spb_rpr_check_db = 0x10, isc_spb_rpr_ignore_checksum = 0x20, isc_spb_rpr_kill_shadows = 0x40, isc_spb_rpr_full = 0x80, isc_spb_rpr_icu = 0x0800; /* · Security Service ·*/ const isc_spb_sec_userid = 5, isc_spb_sec_groupid = 6, isc_spb_sec_username = 7, isc_spb_sec_password = 8, isc_spb_sec_groupname = 9, isc_spb_sec_firstname = 10, isc_spb_sec_middlename = 11, isc_spb_sec_lastname = 12, isc_spb_sec_admin = 13; /* License Service */ const isc_spb_lic_key = 5, isc_spb_lic_id = 6, isc_spb_lic_desc = 7; /* Statistics Service */ const isc_spb_sts_data_pages = 0x01, isc_spb_sts_db_log = 0x02, isc_spb_sts_hdr_pages = 0x04, isc_spb_sts_idx_pages = 0x08, isc_spb_sts_sys_relations = 0x10, isc_spb_sts_record_versions = 0x20, isc_spb_sts_table = 0x40, isc_spb_sts_nocreation = 0x80; /* Trace Service */ const isc_spb_trc_id = 1, isc_spb_trc_name = 2, isc_spb_trc_cfg = 3; /***********************/ /* ISC Error Codes */ /***********************/ const isc_arg_end = 0, // end of argument list isc_arg_gds = 1, // generic DSRI status value isc_arg_string = 2, // string argument isc_arg_cstring = 3, // count & string argument isc_arg_number = 4, // numeric argument (long) isc_arg_interpreted = 5, // interpreted status code (string) isc_arg_unix = 7, // UNIX error code isc_arg_next_mach = 15, // NeXT/Mach error code isc_arg_win32 = 17, // Win32 error code isc_arg_warning = 18, // warning argument isc_arg_sql_state = 19; // SQLSTATE const isc_sqlerr = 335544436; /**********************************/ /* Database parameter block stuff */ /**********************************/ const isc_dpb_version1 = 1, isc_dpb_version2 = 2, // >= FB30 isc_dpb_cdd_pathname = 1, isc_dpb_allocation = 2, isc_dpb_journal = 3, isc_dpb_page_size = 4, isc_dpb_num_buffers = 5, isc_dpb_buffer_length = 6, isc_dpb_debug = 7, isc_dpb_garbage_collect = 8, isc_dpb_verify = 9, isc_dpb_sweep = 10, isc_dpb_enable_journal = 11, isc_dpb_disable_journal = 12, isc_dpb_dbkey_scope = 13, isc_dpb_number_of_users = 14, isc_dpb_trace = 15, isc_dpb_no_garbage_collect = 16, isc_dpb_damaged = 17, isc_dpb_license = 18, isc_dpb_sys_user_name = 19, isc_dpb_encrypt_key = 20, isc_dpb_activate_shadow = 21, isc_dpb_sweep_interval = 22, isc_dpb_delete_shadow = 23, isc_dpb_force_write = 24, isc_dpb_begin_log = 25, isc_dpb_quit_log = 26, isc_dpb_no_reserve = 27, isc_dpb_user_name = 28, isc_dpb_password = 29, isc_dpb_password_enc = 30, isc_dpb_sys_user_name_enc = 31, isc_dpb_interp = 32, isc_dpb_online_dump = 33, isc_dpb_old_file_size = 34, isc_dpb_old_num_files = 35, isc_dpb_old_file = 36, isc_dpb_old_start_page = 37, isc_dpb_old_start_seqno = 38, isc_dpb_old_start_file = 39, isc_dpb_old_dump_id = 41, isc_dpb_lc_messages = 47, isc_dpb_lc_ctype = 48, isc_dpb_cache_manager = 49, isc_dpb_shutdown = 50, isc_dpb_online = 51, isc_dpb_shutdown_delay = 52, isc_dpb_reserved = 53, isc_dpb_overwrite = 54, isc_dpb_sec_attach = 55, isc_dpb_connect_timeout = 57, isc_dpb_dummy_packet_interval = 58, isc_dpb_gbak_attach = 59, isc_dpb_sql_role_name = 60, isc_dpb_set_page_buffers = 61, isc_dpb_working_directory = 62, isc_dpb_sql_dialect = 63, isc_dpb_set_db_readonly = 64, isc_dpb_set_db_sql_dialect = 65, isc_dpb_gfix_attach = 66, isc_dpb_gstat_attach = 67, isc_dpb_set_db_charset = 68, isc_dpb_gsec_attach = 69, isc_dpb_address_path = 70, isc_dpb_process_id = 71, isc_dpb_no_db_triggers = 72, isc_dpb_trusted_auth = 73, isc_dpb_process_name = 74, isc_dpb_trusted_role = 75, isc_dpb_org_filename = 76, isc_dpb_utf8_filename = 77, isc_dpb_ext_call_depth = 78, // Firebird 3.0 constants isc_dpb_auth_block = 79, isc_dpb_client_version = 80, isc_dpb_remote_protocol = 81, isc_dpb_host_name = 82, isc_dpb_os_user = 83, isc_dpb_specific_auth_data = 84, isc_dpb_auth_plugin_list = 85, isc_dpb_auth_plugin_name = 86, isc_dpb_config = 87, isc_dpb_nolinger = 88, isc_dpb_reset_icu = 89, isc_dpb_map_attach = 90, // Firebird 4 constants isc_dpb_session_time_zone = 91, isc_dpb_set_db_replica = 92, isc_dpb_set_bind = 93, isc_dpb_decfloat_round = 94, isc_dpb_decfloat_traps = 95; /*************************************/ /* Services parameter block stuff */ /*************************************/ const isc_spb_version1 = 1, isc_spb_current_version = 2, isc_spb_version = isc_spb_current_version, isc_spb_user_name = isc_dpb_user_name, isc_spb_sys_user_name = isc_dpb_sys_user_name, isc_spb_sys_user_name_enc = isc_dpb_sys_user_name_enc, isc_spb_password = isc_dpb_password, isc_spb_password_enc = isc_dpb_password_enc, isc_spb_command_line = 105, isc_spb_dbname = 106, isc_spb_verbose = 107, isc_spb_options = 108, isc_spb_address_path = 109, isc_spb_process_id = 110, isc_spb_trusted_auth = 111, // This will not be used in protocol 13, therefore may be reused isc_spb_specific_auth_data = isc_spb_trusted_auth, isc_spb_process_name = 112, isc_spb_trusted_role = 113, isc_spb_verbint = 114, isc_spb_auth_block = 115, isc_spb_auth_plugin_name = 116, isc_spb_auth_plugin_list = 117, isc_spb_utf8_filename = 118, isc_spb_client_version = 119, isc_spb_remote_protocol = 120, isc_spb_host_name = 121, isc_spb_os_user = 122, isc_spb_config = 123, isc_spb_expected_db = 124; /*************************************/ /* Transaction parameter block stuff */ /*************************************/ const isc_tpb_version1 = 1, isc_tpb_version3 = 3, isc_tpb_consistency = 1, isc_tpb_concurrency = 2, isc_tpb_shared = 3, // < FB21 isc_tpb_protected = 4, // < FB21 isc_tpb_exclusive = 5, // < FB21 isc_tpb_wait = 6, isc_tpb_nowait = 7, isc_tpb_read = 8, isc_tpb_write = 9, isc_tpb_lock_read = 10, isc_tpb_lock_write = 11, isc_tpb_verb_time = 12, isc_tpb_commit_time = 13, isc_tpb_ignore_limbo = 14, isc_tpb_read_committed = 15, isc_tpb_autocommit = 16, isc_tpb_rec_version = 17, isc_tpb_no_rec_version = 18, isc_tpb_restart_requests = 19, isc_tpb_no_auto_undo = 20, isc_tpb_lock_timeout = 21; // >= FB20 /****************************/ /* Common, structural codes */ /****************************/ const isc_info_end = 1, isc_info_truncated = 2, isc_info_error = 3, isc_info_data_not_ready = 4, isc_info_length = 126, isc_info_flag_end = 127; /*************************/ /* SQL information items */ /*************************/ const isc_info_sql_select = 4, isc_info_sql_bind = 5, isc_info_sql_num_variables = 6, isc_info_sql_describe_vars = 7, isc_info_sql_describe_end = 8, isc_info_sql_sqlda_seq = 9, isc_info_sql_message_seq = 10, isc_info_sql_type = 11, isc_info_sql_sub_type = 12, isc_info_sql_scale = 13, isc_info_sql_length = 14, isc_info_sql_null_ind = 15, isc_info_sql_field = 16, isc_info_sql_relation = 17, isc_info_sql_owner = 18, isc_info_sql_alias = 19, isc_info_sql_sqlda_start = 20, isc_info_sql_stmt_type = 21, isc_info_sql_get_plan = 22, isc_info_sql_records = 23, isc_info_sql_batch_fetch = 24, isc_info_sql_relation_alias = 25, // >= 2.0 isc_info_sql_explain_plan = 26; // >= 3.0 /*******************/ /* Blr definitions */ /*******************/ const blr_text = 14, blr_text2 = 15, blr_short = 7, blr_long = 8, blr_quad = 9, blr_float = 10, blr_double = 27, blr_d_float = 11, blr_timestamp = 35, blr_varying = 37, blr_varying2 = 38, blr_blob = 261, blr_cstring = 40, blr_cstring2 = 41, blr_blob_id = 45, blr_sql_date = 12, blr_sql_time = 13, blr_int64 = 16, blr_blob2 = 17, // >= 2.0 blr_domain_name = 18, // >= 2.1 blr_domain_name2 = 19, // >= 2.1 blr_not_nullable = 20, // >= 2.1 blr_column_name = 21, // >= 2.5 blr_column_name2 = 22, // >= 2.5 blr_bool = 23, // >= 3.0 blr_version4 = 4, blr_version5 = 5, // dialect 3 blr_eoc = 76, blr_end = 255, blr_assignment = 1, blr_begin = 2, blr_dcl_variable = 3, blr_message = 4; const isc_info_sql_stmt_select = 1, isc_info_sql_stmt_insert = 2, isc_info_sql_stmt_update = 3, isc_info_sql_stmt_delete = 4, isc_info_sql_stmt_ddl = 5, isc_info_sql_stmt_get_segment = 6, isc_info_sql_stmt_put_segment = 7, isc_info_sql_stmt_exec_procedure = 8, isc_info_sql_stmt_start_trans = 9, isc_info_sql_stmt_commit = 10, isc_info_sql_stmt_rollback = 11, isc_info_sql_stmt_select_for_upd = 12, isc_info_sql_stmt_set_generator = 13, isc_info_sql_stmt_savepoint = 14; const isc_blob_text = 1; const DESCRIBE = [ isc_info_sql_stmt_type, isc_info_sql_select, isc_info_sql_describe_vars, isc_info_sql_sqlda_seq, isc_info_sql_type, isc_info_sql_sub_type, isc_info_sql_scale, isc_info_sql_length, isc_info_sql_field, isc_info_sql_relation, //isc_info_sql_owner, isc_info_sql_alias, isc_info_sql_describe_end, isc_info_sql_bind, isc_info_sql_describe_vars, isc_info_sql_sqlda_seq, isc_info_sql_type, isc_info_sql_sub_type, isc_info_sql_scale, isc_info_sql_length, isc_info_sql_describe_end ]; const ISOLATION_READ_UNCOMMITTED = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_read_committed, isc_tpb_no_rec_version], ISOLATION_READ_COMMITED_NO_WAIT = [isc_tpb_version3, isc_tpb_write, isc_tpb_nowait, isc_tpb_read_committed, isc_tpb_rec_version], ISOLATION_READ_COMMITED = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_read_committed, isc_tpb_rec_version], ISOLATION_REPEATABLE_READ = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_concurrency], ISOLATION_SERIALIZABLE = [isc_tpb_version3, isc_tpb_write, isc_tpb_wait, isc_tpb_consistency], ISOLATION_READ_COMMITED_READ_ONLY = [isc_tpb_version3, isc_tpb_read, isc_tpb_wait, isc_tpb_read_committed, isc_tpb_no_rec_version]; const DEFAULT_HOST = '127.0.0.1', DEFAULT_PORT = 3050, DEFAULT_USER = 'SYSDBA', DEFAULT_PASSWORD = 'masterkey', DEFAULT_LOWERCASE_KEYS = false, DEFAULT_PAGE_SIZE = 4096, DEFAULT_SVC_NAME = 'service_mgr'; const AUTH_PLUGIN_LEGACY = 'Legacy_Auth'; const AUTH_PLUGIN_LIST = [AUTH_PLUGIN_LEGACY], LEGACY_AUTH_SALT = '9z'; exports.ISOLATION_READ_UNCOMMITTED = ISOLATION_READ_UNCOMMITTED; exports.ISOLATION_READ_COMMITED_NO_WAIT = ISOLATION_READ_COMMITED_NO_WAIT; exports.ISOLATION_READ_COMMITED = ISOLATION_READ_COMMITED; exports.ISOLATION_REPEATABLE_READ = ISOLATION_REPEATABLE_READ; exports.ISOLATION_SERIALIZABLE = ISOLATION_SERIALIZABLE; exports.ISOLATION_READ_COMMITED_READ_ONLY = ISOLATION_READ_COMMITED_READ_ONLY; /** * Escape value * @param {Object} value * @return {String} */ exports.escape = function (value) { if (value === null || value === undefined) { return 'NULL'; } switch (typeof (value)) { case 'boolean': return value ? '1' : '0'; case 'number': return value.toString(); case 'string': return "'" + value.replace(/'/g, "''").replace(/\\/g, '\\\\') + "'"; } if (value instanceof Date) { return "'" + value.getFullYear() + '-' + (value.getMonth() + 1).toString().padStart(2, '0') + '-' + value.getDate().toString().padStart(2, '0') + ' ' + value.getHours().toString().padStart(2, '0') + ':' + value.getMinutes().toString().padStart(2, '0') + ':' + value.getSeconds().toString().padStart(2, '0') + '.' + value.getMilliseconds().toString().padStart(3, '0') + "'"; } throw new Error('Escape supports only primitive values.'); }; const DEFAULT_FETCHSIZE = 600, DEFAULT_FETCHSIZE_BLOB = 60; const BLOB_MAX = 16384; const MAX_INT = Math.pow(2, 31) - 1, MIN_INT = -Math.pow(2, 31); /*************************************** * * SQLVar * ***************************************/ const ScaleDivisor = [1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000, 100000000000, 1000000000000, 10000000000000, 100000000000000, 1000000000000000]; const DateOffset = 40587, TimeCoeff = 86400000, MsPerMinute = 60000; //------------------------------------------------------ function SQLVarText() { } SQLVarText.prototype.decode = function (data, lowerV13, encoding) { let ret; if (this.subType > 1) { ret = data.readText(this.length, encoding); } else { ret = data.readBuffer(this.length); } if (!lowerV13 || !data.readInt()) { if (Buffer.isBuffer(ret)) { return ret.toString(encoding).trim(); } else if (ret) { return ret.trim(); } else { return ret; } } return null; }; SQLVarText.prototype.calcBlr = function (blr) { blr.addByte(blr_text); blr.addWord(this.length); }; //------------------------------------------------------ function SQLVarNull() { } SQLVarNull.prototype = new SQLVarText(); SQLVarNull.prototype.constructor = SQLVarNull; //------------------------------------------------------ function SQLVarString() { } SQLVarString.prototype.decode = function (data, lowerV13, encoding) { let ret; if (this.subType > 1) { ret = data.readString(encoding); } else { ret = data.readBuffer(); } if (!lowerV13 || !data.readInt()) { if (Buffer.isBuffer(ret)) { return ret.toString(encoding).trim(); } else if (ret) { return ret.trim(); } else { return ret; } } return null; }; SQLVarString.prototype.calcBlr = function (blr) { blr.addByte(blr_varying); blr.addWord(this.length); }; //------------------------------------------------------ function SQLVarQuad() { } SQLVarQuad.prototype.decode = function (data, lowerV13) { var ret = data.readQuad(); if (!lowerV13 || !data.readInt()) { return ret; } return null; }; SQLVarQuad.prototype.calcBlr = function (blr) { blr.addByte(blr_quad); blr.addShort(this.scale); }; //------------------------------------------------------ function SQLVarBlob() { } SQLVarBlob.prototype = new SQLVarQuad(); SQLVarBlob.prototype.constructor = SQLVarBlob; SQLVarBlob.prototype.calcBlr = function (blr) { blr.addByte(blr_quad); blr.addShort(0); }; //------------------------------------------------------ function SQLVarArray() { } SQLVarArray.prototype = new SQLVarQuad(); SQLVarArray.prototype.constructor = SQLVarArray; SQLVarArray.prototype.calcBlr = function (blr) { blr.addByte(blr_quad); blr.addShort(0); }; //------------------------------------------------------ function SQLVarInt() { } SQLVarInt.prototype.decode = function (data, lowerV13) { var ret = data.readInt(); if (this.scale) { ret = ret / ScaleDivisor[Math.abs(this.scale)]; } if (!lowerV13 || !data.readInt()) { return ret; } return null; }; SQLVarInt.prototype.calcBlr = function (blr) { blr.addByte(blr_long); blr.addShort(this.scale); }; //------------------------------------------------------ function SQLVarShort() { } SQLVarShort.prototype = new SQLVarInt(); SQLVarShort.prototype.constructor = SQLVarShort; SQLVarShort.prototype.calcBlr = function (blr) { blr.addByte(blr_short); blr.addShort(this.scale); }; //------------------------------------------------------ function SQLVarInt64() { } SQLVarInt64.prototype.decode = function (data, lowerV13) { var ret = data.readInt64(); if (this.scale) { ret = ret / ScaleDivisor[Math.abs(this.scale)]; } if (!lowerV13 || !data.readInt()) { return ret; } return null; }; SQLVarInt64.prototype.calcBlr = function (blr) { blr.addByte(blr_int64); blr.addShort(this.scale); }; //------------------------------------------------------ function SQLVarFloat() { } SQLVarFloat.prototype.decode = function (data, lowerV13) { var ret = data.readFloat(); if (!lowerV13 || !data.readInt()) { return ret; } return null; }; SQLVarFloat.prototype.calcBlr = function (blr) { blr.addByte(blr_float); }; //------------------------------------------------------ function SQLVarDouble() { } SQLVarDouble.prototype.decode = function (data, lowerV13) { var ret = data.readDouble(); if (!lowerV13 || !data.readInt()) { return ret; } return null; }; SQLVarDouble.prototype.calcBlr = function (blr) { blr.addByte(blr_double); }; //------------------------------------------------------ function SQLVarDate() { } SQLVarDate.prototype.decode = function (data, lowerV13) { var ret = data.readInt(); if (!lowerV13 || !data.readInt()) { var d = new Date(0); d.setMilliseconds((ret - DateOffset) * TimeCoeff + d.getTimezoneOffset() * MsPerMinute); return d; } return null; }; SQLVarDate.prototype.calcBlr = function (blr) { blr.addByte(blr_sql_date); }; //------------------------------------------------------ function SQLVarTime() { } SQLVarTime.prototype.decode = function (data, lowerV13) { var ret = data.readUInt(); if (!lowerV13 || !data.readInt()) { var d = new Date(0); d.setMilliseconds(Math.floor(ret / 10) + d.getTimezoneOffset() * MsPerMinute); return d; } return null; }; SQLVarTime.prototype.calcBlr = function (blr) { blr.addByte(blr_sql_time); }; //------------------------------------------------------ function SQLVarTimeStamp() { } SQLVarTimeStamp.prototype.decode = function (data, lowerV13) { var date = data.readInt(); var time = data.readUInt(); if (!lowerV13 || !data.readInt()) { var d = new Date(0); d.setMilliseconds((date - DateOffset) * TimeCoeff + Math.floor(time / 10) + d.getTimezoneOffset() * MsPerMinute); return d; } return null; }; SQLVarTimeStamp.prototype.calcBlr = function (blr) { blr.addByte(blr_timestamp); }; //------------------------------------------------------ function SQLVarBoolean() { } SQLVarBoolean.prototype.decode = function (data, lowerV13) { var ret = data.readInt(); if (!lowerV13 || !data.readInt()) { return Boolean(ret); } return null; }; SQLVarBoolean.prototype.calcBlr = function (blr) { blr.addByte(blr_bool); }; //------------------------------------------------------ function SQLParamInt(value) { this.value = value; } SQLParamInt.prototype.calcBlr = function (blr) { blr.addByte(blr_long); blr.addShort(0); }; SQLParamInt.prototype.encode = function (data) { if (this.value != null) { data.addInt(this.value); } else { data.addInt(0); data.addInt(1); } }; //------------------------------------------------------ function SQLParamInt64(value) { this.value = value; } SQLParamInt64.prototype.calcBlr = function (blr) { blr.addByte(blr_int64); blr.addShort(0); }; SQLParamInt64.prototype.encode = function (data) { if (this.value != null) { data.addInt64(this.value); } else { data.addInt64(0); data.addInt(1); } }; //------------------------------------------------------ function SQLParamDouble(value) { this.value = value; } SQLParamDouble.prototype.encode = function (data) { if (this.value != null) { data.addDouble(this.value); } else { data.addDouble(0); data.addInt(1); } }; SQLParamDouble.prototype.calcBlr = function (blr) { blr.addByte(blr_double); }; //------------------------------------------------------ function SQLParamString(value) { this.value = value; } SQLParamString.prototype.encode = function (data, encoding) { if (this.value != null) { data.addText(this.value, encoding); } else { data.addInt(1); } }; SQLParamString.prototype.calcBlr = function (blr, encoding) { blr.addByte(blr_text); var len = this.value ? Buffer.byteLength(this.value, encoding) : 0; blr.addWord(len); }; //------------------------------------------------------ function SQLParamQuad(value) { this.value = value; } SQLParamQuad.prototype.encode = function (data) { if (this.value != null) { data.addInt(this.value.high); data.addInt(this.value.low); } else { data.addInt(0); data.addInt(0); data.addInt(1); } }; SQLParamQuad.prototype.calcBlr = function (blr) { blr.addByte(blr_quad); blr.addShort(0); }; //------------------------------------------------------ function SQLParamDate(value) { this.value = value; } SQLParamDate.prototype.encode = function (data) { if (this.value != null) { var value = this.value.getTime() - this.value.getTimezoneOffset() * MsPerMinute; var time = value % TimeCoeff; var date = (value - time) / TimeCoeff + DateOffset; time *= 10; // check overflow if (time < 0) { date--; time = TimeCoeff * 10 + time; } data.addInt(date); data.addUInt(time); } else { data.addInt(0); data.addUInt(0); data.addInt(1); } }; SQLParamDate.prototype.calcBlr = function (blr) { blr.addByte(blr_timestamp); }; //------------------------------------------------------ function SQLParamBool(value) { this.value = value; } SQLParamBool.prototype.encode = function (data) { if (this.value != null) { data.addInt(this.value ? 1 : 0); } else { data.addInt(0); data.addInt(1); } }; SQLParamBool.prototype.calcBlr = function (blr) { blr.addByte(blr_short); blr.addShort(0); }; /*************************************** * * Error handling * ***************************************/ function isError(obj) { return (obj instanceof Object && obj.status); } function doCallback(obj, callback) { if (!callback) { return; } if (obj instanceof Error) { doError(obj, callback); return; } if (isError(obj)) { callback(new GDSError(obj)); return; } callback(undefined, obj); } function doError(obj, callback) { if (callback) { if (obj && obj.message) { let errTemp = obj.message + ''; if (errTemp && (errTemp.includes('At procedure') || errTemp.includes('At trigger') || errTemp.includes('GENERICA, '))) { errTemp = errTemp.replace(/Error: exception [0-9]{2}, /, ''); errTemp = errTemp.replace(/Error: validation error for column /g, ''); errTemp = errTemp.replace(/^[A-Z]+(?:_[A-Z]+)+, /, ''); errTemp = errTemp.replace(/GENERICA, /g, ''); errTemp = errTemp.replace(/C!/g, 'á'); errTemp = errTemp.replace(/C'/g, 'ç'); errTemp = errTemp.replace(/C:/g, 'ú'); errTemp = errTemp.replace(/C3/g, 'ó'); errTemp = errTemp.replace(/C#/g, 'ã'); errTemp = errTemp.replace(/C-/g, 'í'); obj.message = errTemp; } } callback(obj); } } /*************************************** * * Statement * ***************************************/ function Statement(connection) { this.connection = connection; this.close = function (callback) { this.connection.closeStatement(this, callback); }; this.drop = function (callback) { this.connection.dropStatement(this, callback); }; this.release = function (callback) { var cache_query = this.connection.getCachedQuery(this.query); if (cache_query) { this.connection.closeStatement(this, callback); } else { this.connection.dropStatement(this, callback); } }; this.execute = function (transaction, params, callback, custom) { if (params instanceof Function) { custom = callback; callback = params; params = undefined; } this.custom = custom; this.connection.executeStatement(transaction, this, params, callback); }; this.fetch = function (transaction, count, callback) { this.connection.fetch(this, transaction, count, callback); }; this.fetchAll = function (transaction, callback) { this.connection.fetchAll(this, transaction, callback); }; } /*************************************** * * Transaction * ***************************************/ function Transaction(connection) { this.connection = connection; this.db = connection.db; this.newStatement = function (query, callback) { var cnx = this.connection; var self = this; var query_cache = cnx.getCachedQuery(query); if (query_cache) { callback(null, query_cache); } else { cnx.prepare(self, query, false, callback); } }; this.executeAux = function (query, params, callback, custom) { if (params instanceof Function) { custom = callback; callback = params; params = undefined; } var self = this; this.newStatement(query, function (err, statement) { if (err) { doError(err, callback); return; } function dropError(err) { statement.release(); doCallback(err, callback); } statement.execute(self, params, function (err, ret) { if (err) { dropError(err); return; } switch (statement.type) { case isc_info_sql_stmt_select: statement.fetchAll(self, function (err, r) { if (err) { dropError(err); return; } statement.release(); if (callback) { callback(undefined, r, statement.output, true); } }); break; case isc_info_sql_stmt_exec_procedure: if (ret && ret.data && ret.data.length > 0) { statement.release(); if (callback) { callback(undefined, ret.data[0], statement.output, true); } break; } else if (statement.output.length) { statement.fetch(self, 1, function (err, ret) { if (err) { dropError(err); return; } statement.release(); if (callback) { callback(undefined, ret.data[0], statement.output, false); } }); break; } // Fall through is normal default: statement.release(); if (callback) { callback(); } break; } }, custom); }); }; this.sequentially = function (query, params, on, callback, asArray) { if (params instanceof Function) { asArray = callback; callback = on; on = params; params = undefined; } if (callback instanceof Boolean) { asArray = callback; callback = undefined; } let self = this; let promise = new Promise((resolve, reject) => { if (on === undefined) { reject(new Error('Expected "on" delegate.')); } else { self.executeAux(query, params, (err) => { if (err) { return reject(err); } else { return resolve(); } }, {asObject: !asArray, asStream: true, on: on}); } return self; }); if (callback) { return promise.then(_ => { return callback(undefined); }).catch(e => { return callback(e); }); } return promise; }; this.execute = function (query, params, queryLimit, callback) { if (params instanceof Function) { callback = params; params = undefined; } if (queryLimit instanceof Function) { callback = queryLimit; queryLimit = undefined; } let self = this; let promise = new Promise((resolve, reject) => { self.executeAux(query, params, (err, result) => { if (err) { return reject(err); } else { return resolve(result); } }, {queryLimit: queryLimit}); return self; }); if (callback) { return promise.then(d => { return callback(undefined, d); }).catch(e => { return callback(e); }); } return promise; }; this.executeOne = function (query, params, callback) { if (params instanceof Function) { callback = params; params = undefined; } let self = this; let promise = new Promise((resolve, reject) => { self.executeAux(query, params, (err, result) => { if (err) { return reject(err); } else if (result && result.length > 0) { return resolve(result[0]); } else { return resolve(null); } }, undefined); return self; }); if (callback) { return promise.then(d => { return callback(undefined, d); }).catch(e => { return callback(e); }); } return promise; }; this.query = function (query, params, queryLimit, callback) { if (params instanceof Function) { callback = params; params = undefined; } if (queryLimit instanceof Function) { callback = queryLimit; queryLimit = undefined; } let self = this; let promise =