/* KInterbasDB Python Package - Implementation of DB API Constant Transfer to
 *                              Python Objects
 *
 * Version 3.3
 *
 * The following contributors hold Copyright (C) over their respective
 * portions of code (see license.txt for details):
 *
 * [Original Author (maintained through version 2.0-0.3.1):]
 *   1998-2001 [alex]  Alexander Kuznetsov   <alexan@users.sourceforge.net>
 * [Maintainers (after version 2.0-0.3.1):]
 *   2001-2002 [maz]   Marek Isalski         <kinterbasdb@maz.nu>
 *   2002-2007 [dsr]   David Rushby          <woodsplitter@rocketmail.com>
 * [Contributors:]
 *   2001      [eac]   Evgeny A. Cherkashin  <eugeneai@icc.ru>
 *   2001-2002 [janez] Janez Jere            <janez.jere@void.si>
 */

/* This file is designed to be included directly into _kinterbasdb.c without
 * the involvement of a header file. */

/* YYY: In the macros below, theoretically ought to DECREF the created
 * constant (though in practice, that'll slow down module init a little, and
 * the objects never die, so there's no practical difference). */

/* SIC is just a shortcut for entering integer database info constants into
 * dict d. */
#define SIC(name) \
  py_const = PyInt_FromLong(name); \
  if (py_const == NULL || PyDict_SetItemString(d, #name, py_const) != 0) { \
    return; \
  }

/* SIC_TO doesn't require that $name be defined; the caller must specify the
 * value. */
#define SIC_TO(name, value) \
  py_const = PyInt_FromLong(value); \
  if (py_const == NULL || PyDict_SetItemString(d, #name, py_const) != 0) { \
    return; \
  }

/* SET_PARAMBUF_CONST is just a shortcut for defining transaction parameter buffer
 * constants (or those of a similar format, such as database parameter buffer
 * constants), which were previously defined in kinterbasdb.py as strings
 * containing octal escape codes.
 *
 * For example, if the definition of isc_some_dumb_const were:
 *   #define isc_some_dumb_const 16
 * then the brittle version of the Python would feature this line:
 *   isc_some_dumb_const = '\020'
 *
 * The point of SET_PARAMBUF_CONST is to enter into dict d the equivalent of the
 * Python string '\020', when passed the name of isc_some_dumb_const. */
#define SET_PARAMBUF_CONST(name) \
  convArray[0] = (char) name; \
  py_const = PyString_FromStringAndSize(convArray, 1); \
  if (py_const == NULL || PyDict_SetItemString(d, #name, py_const) != 0) { \
    return; \
  }

static void _init_kidb_general(PyObject *d) {
  /* These constants are defined by kinterbasdb rather than by the database
   * engine's C API. */
  PyObject *py_const;

  SIC(DIST_TRANS_MAX_DATABASES);

  #ifdef ENABLE_CONNECTION_TIMEOUT
    SIC(CT_VETO);
    SIC(CT_ROLLBACK);
    SIC(CT_COMMIT);
    SIC(CT_DEFAULT);
    SIC(CT_NONTRANSPARENT);
  #endif /* ENABLE_CONNECTION_TIMEOUT */
} /* _init_kidb_ibase_header_constants_general */

static void _init_kidb_ibase_header_constants_general(PyObject *d) {
  char convArray[1];
  PyObject *py_const;

  /* When testing for the presence of certain constants, it'd be better to use
   * #ifdef than to hard-code assumptions about which versions of the engine
   * have which constants, but some of the constants are defined as enums
   * rather than via the preprocessor.  If their inclusion is #ifdefed, they
   * of course are not included. */
  #ifdef FIREBIRD_1_0_OR_LATER
  SIC(isc_info_isc_version);
  #endif
  /* isc_info_version is apparently a deprecated form of isc_info_isc_version. */
  SIC(isc_info_version);

  SET_PARAMBUF_CONST(isc_dpb_version1);
  SET_PARAMBUF_CONST(isc_dpb_cdd_pathname);
  SET_PARAMBUF_CONST(isc_dpb_allocation);
  SET_PARAMBUF_CONST(isc_dpb_journal);
  SET_PARAMBUF_CONST(isc_dpb_page_size);
  SET_PARAMBUF_CONST(isc_dpb_num_buffers);
  SET_PARAMBUF_CONST(isc_dpb_buffer_length);
  SET_PARAMBUF_CONST(isc_dpb_debug);
  SET_PARAMBUF_CONST(isc_dpb_garbage_collect);
  SET_PARAMBUF_CONST(isc_dpb_verify);
  SET_PARAMBUF_CONST(isc_dpb_sweep);
  SET_PARAMBUF_CONST(isc_dpb_enable_journal);
  SET_PARAMBUF_CONST(isc_dpb_disable_journal);
  SET_PARAMBUF_CONST(isc_dpb_dbkey_scope);
  SET_PARAMBUF_CONST(isc_dpb_number_of_users);
  SET_PARAMBUF_CONST(isc_dpb_trace);
  SET_PARAMBUF_CONST(isc_dpb_no_garbage_collect);
  SET_PARAMBUF_CONST(isc_dpb_damaged);
  SET_PARAMBUF_CONST(isc_dpb_license);
  SET_PARAMBUF_CONST(isc_dpb_sys_user_name);
  SET_PARAMBUF_CONST(isc_dpb_encrypt_key);
  SET_PARAMBUF_CONST(isc_dpb_activate_shadow);
  SET_PARAMBUF_CONST(isc_dpb_sweep_interval);
  SET_PARAMBUF_CONST(isc_dpb_delete_shadow);
  SET_PARAMBUF_CONST(isc_dpb_force_write);
  SET_PARAMBUF_CONST(isc_dpb_begin_log);
  SET_PARAMBUF_CONST(isc_dpb_quit_log);
  SET_PARAMBUF_CONST(isc_dpb_no_reserve);
  SET_PARAMBUF_CONST(isc_dpb_user_name);
  SET_PARAMBUF_CONST(isc_dpb_password);
  SET_PARAMBUF_CONST(isc_dpb_password_enc);
  SET_PARAMBUF_CONST(isc_dpb_sys_user_name_enc);
  SET_PARAMBUF_CONST(isc_dpb_interp);
  SET_PARAMBUF_CONST(isc_dpb_online_dump);
  SET_PARAMBUF_CONST(isc_dpb_old_file_size);
  SET_PARAMBUF_CONST(isc_dpb_old_num_files);
  SET_PARAMBUF_CONST(isc_dpb_old_file);
  SET_PARAMBUF_CONST(isc_dpb_old_start_page);
  SET_PARAMBUF_CONST(isc_dpb_old_start_seqno);
  SET_PARAMBUF_CONST(isc_dpb_old_start_file);
  SET_PARAMBUF_CONST(isc_dpb_drop_walfile);
  SET_PARAMBUF_CONST(isc_dpb_old_dump_id);
  SET_PARAMBUF_CONST(isc_dpb_wal_backup_dir);
  SET_PARAMBUF_CONST(isc_dpb_wal_chkptlen);
  SET_PARAMBUF_CONST(isc_dpb_wal_numbufs);
  SET_PARAMBUF_CONST(isc_dpb_wal_bufsize);
  SET_PARAMBUF_CONST(isc_dpb_wal_grp_cmt_wait);
  SET_PARAMBUF_CONST(isc_dpb_lc_messages);
  SET_PARAMBUF_CONST(isc_dpb_lc_ctype);
  SET_PARAMBUF_CONST(isc_dpb_cache_manager);
  SET_PARAMBUF_CONST(isc_dpb_shutdown);
  SET_PARAMBUF_CONST(isc_dpb_online);
  SET_PARAMBUF_CONST(isc_dpb_shutdown_delay);
  SET_PARAMBUF_CONST(isc_dpb_reserved);
  SET_PARAMBUF_CONST(isc_dpb_overwrite);
  SET_PARAMBUF_CONST(isc_dpb_sec_attach);
  SET_PARAMBUF_CONST(isc_dpb_disable_wal);
  SET_PARAMBUF_CONST(isc_dpb_connect_timeout);
  SET_PARAMBUF_CONST(isc_dpb_dummy_packet_interval);
  SET_PARAMBUF_CONST(isc_dpb_gbak_attach);
  SET_PARAMBUF_CONST(isc_dpb_sql_role_name);
  SET_PARAMBUF_CONST(isc_dpb_set_page_buffers);
  SET_PARAMBUF_CONST(isc_dpb_working_directory);
  SET_PARAMBUF_CONST(isc_dpb_sql_dialect);
  SET_PARAMBUF_CONST(isc_dpb_set_db_readonly);
  SET_PARAMBUF_CONST(isc_dpb_set_db_sql_dialect);
  SET_PARAMBUF_CONST(isc_dpb_gfix_attach);
  SET_PARAMBUF_CONST(isc_dpb_gstat_attach);
  #ifdef isc_dpb_set_db_charset
    SET_PARAMBUF_CONST(isc_dpb_set_db_charset);
  #endif
  #ifdef isc_dpb_gsec_attach
    SET_PARAMBUF_CONST(isc_dpb_gsec_attach);
  #endif
  #ifdef isc_dpb_address_path
    SET_PARAMBUF_CONST(isc_dpb_address_path);
  #endif

} /* _init_kidb_ibase_header_constants_general */

static void _init_kidb_ibase_header_constants_transaction_parameters(PyObject *d) {
  char convArray[1];
  PyObject *py_const;

  SET_PARAMBUF_CONST(isc_tpb_version3);

  SET_PARAMBUF_CONST(isc_tpb_consistency);
  SET_PARAMBUF_CONST(isc_tpb_concurrency);
  SET_PARAMBUF_CONST(isc_tpb_shared);
  SET_PARAMBUF_CONST(isc_tpb_protected);
  SET_PARAMBUF_CONST(isc_tpb_exclusive);
  SET_PARAMBUF_CONST(isc_tpb_wait);
  SET_PARAMBUF_CONST(isc_tpb_nowait);
  SET_PARAMBUF_CONST(isc_tpb_read);
  SET_PARAMBUF_CONST(isc_tpb_write);
  SET_PARAMBUF_CONST(isc_tpb_lock_read);
  SET_PARAMBUF_CONST(isc_tpb_lock_write);
  SET_PARAMBUF_CONST(isc_tpb_verb_time);
  SET_PARAMBUF_CONST(isc_tpb_commit_time);
  SET_PARAMBUF_CONST(isc_tpb_ignore_limbo);
  SET_PARAMBUF_CONST(isc_tpb_read_committed);
  SET_PARAMBUF_CONST(isc_tpb_autocommit);
  SET_PARAMBUF_CONST(isc_tpb_rec_version);
  SET_PARAMBUF_CONST(isc_tpb_no_rec_version);
  SET_PARAMBUF_CONST(isc_tpb_restart_requests);
  SET_PARAMBUF_CONST(isc_tpb_no_auto_undo);

  #ifdef HAVE__isc_tpb_lock_timeout
  SET_PARAMBUF_CONST(isc_tpb_lock_timeout);
  #endif
} /* _init_kidb_ibase_header_constants_transaction_parameters */

static void _init_kidb_ibase_header_constants_database_info(PyObject *d) {
  PyObject *py_const;

  SIC(isc_info_db_id);
  SIC(isc_info_reads);
  SIC(isc_info_writes);
  SIC(isc_info_fetches);
  SIC(isc_info_marks);
  SIC(isc_info_implementation);

  SIC(isc_info_base_level);
  SIC(isc_info_page_size);
  SIC(isc_info_num_buffers);
  SIC(isc_info_limbo);
  SIC(isc_info_current_memory);
  SIC(isc_info_max_memory);
  SIC(isc_info_window_turns);
  SIC(isc_info_license);
  SIC(isc_info_allocation);
  SIC(isc_info_attachment_id);
  SIC(isc_info_read_seq_count);
  SIC(isc_info_read_idx_count);
  SIC(isc_info_insert_count);
  SIC(isc_info_update_count);
  SIC(isc_info_delete_count);
  SIC(isc_info_backout_count);
  SIC(isc_info_purge_count);
  SIC(isc_info_expunge_count);
  SIC(isc_info_sweep_interval);
  SIC(isc_info_ods_version);
  SIC(isc_info_ods_minor_version);
  SIC(isc_info_no_reserve);
  SIC(isc_info_logfile);
  SIC(isc_info_cur_logfile_name);
  SIC(isc_info_cur_log_part_offset);
  SIC(isc_info_num_wal_buffers);
  SIC(isc_info_wal_buffer_size);
  SIC(isc_info_wal_ckpt_length);
  SIC(isc_info_wal_cur_ckpt_interval);
  SIC(isc_info_wal_prv_ckpt_fname);
  SIC(isc_info_wal_prv_ckpt_poffset);
  SIC(isc_info_wal_recv_ckpt_fname);
  SIC(isc_info_wal_recv_ckpt_poffset);
  SIC(isc_info_wal_grpc_wait_usecs);
  SIC(isc_info_wal_num_io);
  SIC(isc_info_wal_avg_io_size);
  SIC(isc_info_wal_num_commits);
  SIC(isc_info_wal_avg_grpc_size);
  SIC(isc_info_forced_writes);
  SIC(isc_info_user_names);
  SIC(isc_info_page_errors);
  SIC(isc_info_record_errors);
  SIC(isc_info_bpage_errors);
  SIC(isc_info_dpage_errors);
  SIC(isc_info_ipage_errors);
  SIC(isc_info_ppage_errors);
  SIC(isc_info_tpage_errors);
  SIC(isc_info_set_page_buffers);

  #ifdef INTERBASE_6_OR_LATER
  SIC(isc_info_db_sql_dialect);
  /* Mis-cased version of the above has now been deprecated and is maintained
   * only for compatibility: */
  SIC(isc_info_db_SQL_dialect);

  SIC(isc_info_db_read_only);
  SIC(isc_info_db_size_in_pages);
  #endif /* INTERBASE_6_OR_LATER */

  #ifdef FIREBIRD_1_0_OR_LATER
  SIC(frb_info_att_charset);
  SIC(isc_info_db_class);
  SIC(isc_info_firebird_version);
  SIC(isc_info_oldest_transaction);
  SIC(isc_info_oldest_active);
  SIC(isc_info_oldest_snapshot);
  SIC(isc_info_next_transaction);
  SIC(isc_info_db_provider);
  #else
  /* isc_info_firebird_version is used in __init__.py, but it's not available
   * with Interbase, so we set its value to a flag. */
  SIC_TO(isc_info_firebird_version, -1);
  #endif /* FIREBIRD_1_0_OR_LATER */

  #ifdef FIREBIRD_1_5_OR_LATER
  SIC(isc_info_active_transactions);
  #endif /* FIREBIRD_1_5_OR_LATER */

  /* This HAVE__? silliness is necessary because ibase.h is increasingly not
   * using the preprocessor for constants definitions, so setup.py has to test
   * for the presence of the constants, then use the preprocessor to indicate
   * the result. */
  #ifdef HAVE__isc_info_active_tran_count
    SIC(isc_info_active_tran_count);
  #endif
  #ifdef HAVE__isc_info_creation_date
    SIC(isc_info_creation_date);
  #endif
} /* _init_kidb_ibase_header_constants_database_info */

static void _init_kidb_ibase_header_constants_transaction_info(PyObject *d) {
  PyObject *py_const;

  SIC(isc_info_tra_id);

  #ifdef HAVE__isc_info_tra_oldest_interesting
    SIC(isc_info_tra_oldest_interesting);
  #endif
  #ifdef HAVE__isc_info_tra_oldest_snapshot
    SIC(isc_info_tra_oldest_snapshot);
  #endif
  #ifdef HAVE__isc_info_tra_oldest_active
    SIC(isc_info_tra_oldest_active);
  #endif
  #ifdef HAVE__isc_info_tra_isolation
    SIC(isc_info_tra_isolation);
  #endif
  #ifdef HAVE__isc_info_tra_access
    SIC(isc_info_tra_access);
  #endif
  #ifdef HAVE__isc_info_tra_lock_timeout
    SIC(isc_info_tra_lock_timeout);
  #endif

  #ifdef HAVE__isc_info_tra_consistency
    SIC(isc_info_tra_consistency);
  #endif
  #ifdef HAVE__isc_info_tra_concurrency
    SIC(isc_info_tra_concurrency);
  #endif
  #ifdef HAVE__isc_info_tra_read_committed
    SIC(isc_info_tra_read_committed);
  #endif

  #ifdef HAVE__isc_info_tra_no_rec_version
    SIC(isc_info_tra_no_rec_version);
  #endif
  #ifdef HAVE__isc_info_tra_rec_version
    SIC(isc_info_tra_rec_version);
  #endif

  #ifdef HAVE__isc_info_tra_readonly
    SIC(isc_info_tra_readonly);
  #endif
  #ifdef HAVE__isc_info_tra_readwrite
    SIC(isc_info_tra_readwrite);
  #endif
} /* _init_kidb_ibase_header_constants_transaction_info */

static void _init_kidb_ibase_header_constants_preparedstatement_properties(
    PyObject *d
  )
{
  /* These constants are intended to allow the client programmer to compare the
   * properties of PreparedStatement to symbolic names. */
  PyObject *py_const;

  /* statement_type: */
  SIC(isc_info_sql_stmt_select);
  SIC(isc_info_sql_stmt_insert);
  SIC(isc_info_sql_stmt_update);
  SIC(isc_info_sql_stmt_delete);
  SIC(isc_info_sql_stmt_ddl);
  SIC(isc_info_sql_stmt_get_segment);
  SIC(isc_info_sql_stmt_put_segment);
  SIC(isc_info_sql_stmt_exec_procedure);
  SIC(isc_info_sql_stmt_start_trans);
  SIC(isc_info_sql_stmt_commit);
  SIC(isc_info_sql_stmt_rollback);
  SIC(isc_info_sql_stmt_select_for_upd);
  SIC(isc_info_sql_stmt_set_generator);
  #ifdef FIREBIRD_1_5_OR_LATER
  SIC(isc_info_sql_stmt_savepoint);
  #endif
} /* _init_kidb_ibase_header_constants_preparedstatement_properties */

static PyObject *init_kidb_basic_header_constants(PyObject *self, PyObject *args) {
  PyObject *dest_dict;
  if (!PyArg_ParseTuple(args, "O!", &PyDict_Type, &dest_dict)) { return NULL; }

  _init_kidb_general(dest_dict);
  if (PyErr_Occurred()) { return NULL; }

  _init_kidb_ibase_header_constants_general(dest_dict);
  if (PyErr_Occurred()) { return NULL; }

  _init_kidb_ibase_header_constants_transaction_parameters(dest_dict);
  if (PyErr_Occurred()) { return NULL; }

  _init_kidb_ibase_header_constants_database_info(dest_dict);
  if (PyErr_Occurred()) { return NULL; }

  _init_kidb_ibase_header_constants_transaction_info(dest_dict);
  if (PyErr_Occurred()) { return NULL; }

  _init_kidb_ibase_header_constants_preparedstatement_properties(dest_dict);
  if (PyErr_Occurred()) { return NULL; }

  RETURN_PY_NONE;
} /* init_kidb_ibase_header_constants */
