/*{ ** Name: init_list - initialize list ** ** Description: ** Initializes the linklist, sets the global pointers to null. ** ** Inputs: ** none ** ** Outputs: ** none ** ** Returns: ** none */ void init_list() { if (top) { if (atop) { atop->blink = bottom; bottom->link = atop; atop = top; } else { atop = top; abottom = bottom; } } else { atop = (RLIST *)NULL; abottom = (RLIST *)NULL; } top = (RLIST *)NULL; bottom = (RLIST *)NULL; /* top %d, atop %d */ messageit(5, 1262, top, atop); }
/*{ ** Name: list_top - return the head of the list ** ** Description: ** Returns the top (start) of the list. ** ** Inputs: ** none ** ** Outputs: ** none ** ** Returns: ** A pointer to the head of the list. ** ** Side effects: ** The static pointer current is also pointed to the head of the list. */ RLIST * list_top() { current = top; /* top %d, atop %d */ messageit(5, 1263, top, atop); return (top); }
/*{ ** Name: new_node - new node ** ** Description: ** Create a new structure and append it to the bottom of the linklist. ** ** Inputs: ** none ** ** Outputs: ** none ** ** Returns: ** A pointer to the new node. ** ** Side effects: ** Some of the static pointers above are changed. */ RLIST * new_node() { RLIST *mark; /* top %d, atop %d */ messageit(5, 1264, top, atop); if (atop) { mark = atop; atop = atop->link; } else { mark = (RLIST *)MEreqmem(0, sizeof(RLIST), TRUE, (STATUS *)NULL); if (mark == NULL) { /* Error Allocating Memory for Record List: Aborting */ messageit(1, 1266); RSshutdown(FAIL); } } mark->link = (RLIST *)NULL; mark->blink = (RLIST *)NULL; if (bottom) /* there is already a linklist */ { bottom->link = mark; mark->blink = bottom; bottom = mark; } else /* first structure in the linklist */ { top = mark; bottom = mark; } /* top %d, atop %d, mark %d */ messageit(5, 1265, top, atop, mark); return (mark); }
/*{ ** Name: unquiet_db - unquiet a database ** ** Description: ** Updates the database to mark the specified database number ** as unquiet. ** ** Inputs: ** db_no - database number to be unquieted ** quiet_type - used to specify a USER_QUIET or SERVER_QUIET state ** ** Outputs: ** none ** ** Returns: ** none */ void unquiet_db( i2 db_no, i4 quiet_type) { char stmt[512]; /* Unquieting target database %d */ messageit(2, 1722, db_no); STprintf(stmt, ERx("UPDATE dd_db_cdds SET is_quiet = %d WHERE server_no = %d \ AND database_no = %d AND is_quiet != %d AND is_quiet <= %d"), NOT_QUIET, (i4)RSserver_no, (i4)db_no, NOT_QUIET, quiet_type); if (quiet_update(stmt) != IIAPI_ST_SUCCESS) RSshutdown(FAIL); }
/*{ ** Name: quiet_db - quiet a database ** ** Description: ** Updates the database to mark the specified database number ** as quiet. ** ** Inputs: ** db_no - database number to be quieted ** quiet_type - used to specify a USER_QUIET or SERVER_QUIET state ** ** Outputs: ** none ** ** Returns: ** none */ void quiet_db( i2 db_no, i4 quiet_type) { char stmt[512]; /* Setting target database %d to quiet */ messageit(2, 1718, db_no); STprintf(stmt, ERx("UPDATE dd_db_cdds SET is_quiet = %d WHERE server_no = %d \ AND database_no = %d AND is_quiet < %d"), quiet_type, (i4)RSserver_no, (i4)db_no, quiet_type); if (quiet_update(stmt) != IIAPI_ST_SUCCESS) RSshutdown(FAIL); }
/*{ ** Name: RSmem_allocate - Rep server large memory allocation. ** ** Description: ** Computes and allocates memory size needed for buffers to hold ** replicator server internal queries. ** ** Inputs: ** row_width - Total row width of registered cols. ** num_cols - Number of registered cols. ** colname_space - Maximum name space of registered cols. ** overhead - Additional query overhead ** ** Outputs: ** NONE ** ** Returns: ** buf - NULL or Buffer successfully allocated. */ char * RSmem_allocate( i4 row_width, i4 num_cols, i4 colname_space, i4 overhead) { char *buf = (char *)MEreqmem(0, (num_cols * colname_space + row_width + overhead), TRUE, NULL); if (buf == NULL) { /* Error allocating buf */ messageit(1, 1900); return(buf) ; } return(buf); }
/*{ ** Name: quiet_cdds - quiet a cdds ** ** Description: ** Updates the database to mark the specified cdds number ** as quiet. ** ** Inputs: ** dbno_ptr - database be quieted, NULL for all ** cdds_no - cdds number to be quieted ** quiet_type - used to specify a USER_QUIET or SERVER_QUIET state ** ** Outputs: ** none ** ** Returns: ** none */ void quiet_cdds( i2 *dbno_ptr, i2 cdds_no, i4 quiet_type) { char stmt[512]; if (dbno_ptr == NULL) { /* Setting CDDS %d to quiet */ messageit(2, 1726, cdds_no); STprintf(stmt, ERx("UPDATE dd_db_cdds SET is_quiet = %d WHERE \ server_no = %d AND cdds_no = %d AND is_quiet < %d"), quiet_type, (i4)RSserver_no, (i4)cdds_no, quiet_type); }
/*{ ** Name: RScommit - two-phase commit processing ** ** Description: ** Prepares to commit locally, commits remotely, commits locally. ** Logs each step of the commit so that a reasonable attempt can ** be made to recover if it does not complete. ** ** Inputs: ** target - target database, CDDS and connection number ** row - distribution queue row ** ** Outputs: ** none ** ** Returns: ** OK or Ingres error ** ** Side effects: ** A distributed transaction is committed using incomplete two-phase ** commit (a prepare is only done on the local database, so the target ** database is not aware it is part of a distributed transaction). */ STATUS RScommit( RS_TARGET *target, RS_TRANS_ROW *row) { i4 high = (i4)RSlocal_conn.db_no; SYSTIME now; char timestamp[21]; char timestr[27]; i4 start_entry_no; i4 prepare_entry_no; i4 remote_entry_no; i4 complete_entry_no; RS_TBLDESC *tbl = row->tbl_desc; RS_CONN *local_conn = &RSlocal_conn; RS_CONN *target_conn = &RSconns[target->conn_no]; IIAPI_GETEINFOPARM errParm; IIAPI_STATUS status; if (RStwo_phase) /* two-phase commit is on */ { start_entry_no = RS_2PC_BEGIN; prepare_entry_no = RS_PREP_COMMIT; remote_entry_no = RS_REMOTE_COMMIT; complete_entry_no = RS_2PC_END; } else /* two-phase commit is off */ { start_entry_no = RS_NPC_BEGIN; remote_entry_no = RS_NPC_REM_COMMIT; complete_entry_no = RS_NPC_END; } TMnow(&now); TMstr(&now, timestr); mktimestamp(timestr, timestamp); SIfprintf(RScommit_fp, log_format, start_entry_no, high, low, (i4)target->db_no, tbl->table_owner, tbl->table_name, tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no, timestamp, "Start of commit"); SIflush(RScommit_fp); if (RStwo_phase) /* only prepare to commit if two-phase is on */ { /* ** Prepare to commit. The high value is %d, The low value is %d */ messageit(5, 1277, high, low); status = IIsw_prepareCommit(&local_conn->tranHandle, &errParm); if (status != IIAPI_ST_SUCCESS) { messageit(1, 1214); IIsw_rollback(&target_conn->tranHandle, &errParm); IIsw_rollback(&local_conn->tranHandle, &errParm); IIsw_releaseXID(&dtrans_id_handle); return (status); } SIfprintf(RScommit_fp, log_format, prepare_entry_no, high, low, (i4)target->db_no, tbl->table_owner, tbl->table_name, tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no, timestamp, "Prepare to commit"); SIflush(RScommit_fp); } status = IIsw_commit(&target_conn->tranHandle, &errParm); if (status != IIAPI_ST_SUCCESS) { IIsw_rollback(&target_conn->tranHandle, &errParm); if (IIsw_rollback(&local_conn->tranHandle, &errParm) != IIAPI_ST_SUCCESS) { RSdo_recover = TRUE; messageit(1, 1215); messageit(1, 1216); } else { messageit(1, 1215); } IIsw_releaseXID(&dtrans_id_handle); SIfprintf(RScommit_fp, log_format, remote_entry_no, high, low, (i4)target->db_no, tbl->table_owner, tbl->table_name, tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no, timestamp, "Local rollback"); SIfprintf(RScommit_fp, log_format, complete_entry_no, high, low, (i4)target->db_no, tbl->table_owner, tbl->table_name, tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no, timestamp, "Commit complete"); SIflush(RScommit_fp); return (status); } SIfprintf(RScommit_fp, log_format, remote_entry_no, high, low, (i4)target->db_no, tbl->table_owner, tbl->table_name, tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no, timestamp, "Remote commit"); SIflush(RScommit_fp); status = IIsw_commit(&local_conn->tranHandle, &errParm); if (status != IIAPI_ST_SUCCESS) { RSdo_recover = TRUE; IIsw_releaseXID(&dtrans_id_handle); return (status); } IIsw_releaseXID(&dtrans_id_handle); SIfprintf(RScommit_fp, log_format, complete_entry_no, high, low, (i4)target->db_no, tbl->table_owner, tbl->table_name, tbl->table_no, row->rep_key.trans_id, row->rep_key.seq_no, timestamp, "Commit complete"); SIflush(RScommit_fp); return (OK); }
/*{ ** Name: RSdelete - propagate a DELETE row ** ** Description: ** Propagates a DELETE transaction row, either by calling a remote ** database procedure or by executing a remote DELETE. ** ** Inputs: ** row - row of data ** ** Outputs: ** none ** ** Returns: ** OK ** else - error */ STATUS RSdelete( RS_TARGET *target, RS_TRANS_ROW *row) { char *stmt=NULL; char *proc_name; STATUS err; bool collision_processed = FALSE; RS_TBLDESC *tbl = row->tbl_desc; II_INT2 nparams; IIAPI_DESCRIPTOR pdesc[DB_MAX_COLS+1]; IIAPI_DATAVALUE pdata[DB_MAX_COLS+1]; DB_DELIM_STR *pnames = NULL; RS_CONN *conn = &RSconns[target->conn_no]; II_LONG procRet; II_PTR stmtHandle; IIAPI_GETEINFOPARM errParm; IIAPI_GETQINFOPARM getQinfoParm; IIAPI_STATUS status; IIAPI_DESCRIPTOR *col; IIAPI_DESCRIPTOR *pds; i4 num_cols=tbl->num_regist_cols; i4 row_width=tbl->row_width; stmt = RSmem_allocate(row_width,num_cols,DB_MAXNAME+8,128); if (stmt == NULL) return (FAIL); messageit(5, 1268, row->rep_key.src_db, row->rep_key.trans_id, row->rep_key.seq_no, target->db_no); err = RScollision(target, row, tbl, &collision_processed); if (err || collision_processed) { MEfree((PTR)stmt); return (err); } /* For URO targets, delete the base row. */ if (target->type == TARG_UNPROT_READ) { char *where_list=NULL; char objname[DB_MAXNAME*2+3]; where_list = RSmem_allocate(row_width,tbl->num_key_cols,DB_MAXNAME+8,0); if (where_list == NULL) { MEfree((PTR)stmt); return (FAIL); } /* ** Iterate through key_desc and create the WHERE list and ** prepare the column descriptors. The data will come directly ** from key_data. */ *where_list = EOS; for (col = row->key_desc, pds = pdesc; col < row->key_desc + tbl->num_key_cols; ++col, ++pds) { if (col != row->key_desc) STcat(where_list, ERx(" AND ")); /* ** The following is special case code to allow existing ** customers in non-SQL92 installations to propagate to ** Gateway databases that use uppercase table and ** column names. */ if (conn->name_case == UI_UPPERCASE) { STcopy(col->ds_columnName, objname); CVupper(objname); STcat(where_list, objname); } else { STcat(where_list, col->ds_columnName); } STcat(where_list, ERx(" = ~V")); *pds = *col; /* struct */ pds->ds_columnType = IIAPI_COL_QPARM; } STcopy(tbl->dlm_table_name, objname); if (target->type == TARG_UNPROT_READ && conn->name_case == UI_UPPERCASE) CVupper(objname); STprintf(stmt, ERx("DELETE FROM %s.%s WHERE %s"), tbl->rem_table_owner, objname, where_list); status = IIsw_query(conn->connHandle, &conn->tranHandle, stmt, tbl->num_key_cols, pdesc, row->key_data, NULL, NULL, &stmtHandle, &getQinfoParm, &errParm); status = RSerror_check(1556, ROWS_SINGLE_ROW, stmtHandle, &getQinfoParm, &errParm, NULL, tbl->table_name); MEfree((PTR)where_list); if (status != OK) { MEfree((PTR)stmt); return (status); } } /* For FP and PRO targets, call the remote database procedure. */ else { pnames = (DB_DELIM_STR *)RSmem_allocate(0, DB_MAX_COLS+1, sizeof(*pnames),0); if (pnames == NULL) { MEfree((PTR)stmt); return (FAIL); } proc_name = pnames[0]; if (RPtblobj_name(tbl->table_name, row->table_no, TBLOBJ_REM_DEL_PROC, proc_name) != OK) { messageit(1, 1816, ERx("RSdelete"), tbl->table_name); RSmem_free(stmt, (char *)pnames, NULL, NULL, NULL); return (RS_INTERNAL_ERR); } if (RSpdp_PrepDbprocParams(proc_name, target, tbl, row, pnames, &nparams, pdesc, pdata) != OK) { RSmem_free(stmt, (char *)pnames, NULL, NULL, NULL); return (RS_INTERNAL_ERR); } status = IIsw_execProcedure(conn->connHandle, &conn->tranHandle, nparams, pdesc, pdata, &procRet, &stmtHandle, &getQinfoParm, &errParm); status = RSerror_check(1573, ROWS_DONT_CARE, stmtHandle, &getQinfoParm, &errParm, NULL, proc_name); if (status != OK) { RSmem_free(stmt, (char *)pnames, NULL, NULL, NULL); return (status); } if (procRet) { messageit(1, procRet, row->rep_key.src_db, row->rep_key.trans_id, row->rep_key.seq_no, target->db_no, tbl->table_name); RSmem_free(stmt, (char *)pnames, NULL, NULL, NULL); return (procRet); } } RSstats_update(target->db_no, tbl->table_no, RS_DELETE); if (target->type != TARG_UNPROT_READ) RSmonitor_notify(&RSconns[target->conn_no], RS_INC_DELETE, RSlocal_conn.db_no, tbl->table_name, tbl->table_owner); RSmonitor_notify(&RSlocal_conn, RS_OUT_DELETE, target->db_no, tbl->table_name, tbl->table_owner); RSmem_free(stmt, (char *)pnames, NULL, NULL, NULL); return (OK); }