Пример #1
0
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pgsql_result_t **result_out, int msec)
{
#ifdef SWITCH_HAVE_PGSQL
    switch_pgsql_result_t *res;
    switch_time_t start;
    switch_time_t ctime;
    unsigned int usec = msec * 1000;
    char *err_str;
    struct pollfd fds[2] = { {0} };
    int poll_res = 0;

    if(!handle) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "**BUG** Null handle passed to switch_pgsql_next_result.\n");
        return SWITCH_PGSQL_FAIL;
    }

    /* Try to consume input that might be waiting right away */
    if (PQconsumeInput(handle->con)) {
        /* And check to see if we have a full result ready for reading */
        if (PQisBusy(handle->con)) {

            /* Wait for a result to become available, up to msec milliseconds */
            start = switch_micro_time_now();
            while((ctime = switch_micro_time_now()) - start <= usec) {
                int wait_time = (usec - (ctime - start)) / 1000;
                fds[0].fd = handle->sock;
                fds[0].events |= POLLIN;
                fds[0].events |= POLLERR;
                fds[0].events |= POLLNVAL;
                fds[0].events |= POLLHUP;
                fds[0].events |= POLLPRI;
                fds[0].events |= POLLRDNORM;
                fds[0].events |= POLLRDBAND;

                /* Wait for the PostgreSQL socket to be ready for data reads. */
                if ((poll_res = poll(&fds[0], 1, wait_time)) > 0 ) {
                    if (fds[0].revents & POLLHUP || fds[0].revents & POLLNVAL) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "PGSQL socket closed or invalid while waiting for result for query (%s)\n", handle->sql);
                        goto error;
                    } else if (fds[0].revents & POLLERR) {
                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll error trying to read PGSQL socket for query (%s)\n", handle->sql);
                        goto error;
                    } else if (fds[0].revents & POLLIN || fds[0].revents & POLLPRI || fds[0].revents & POLLRDNORM || fds[0].revents & POLLRDBAND) {
                        /* Then try to consume any input waiting. */
                        if (PQconsumeInput(handle->con)) {
                            if (PQstatus(handle->con) == CONNECTION_BAD) {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Connection terminated while waiting for result.\n");
                                handle->state = SWITCH_PGSQL_STATE_ERROR;
                                goto error;
                            }

                            /* And check to see if we have a full result ready for reading */
                            if (!PQisBusy(handle->con)) {
                                /* If we can pull a full result without blocking, then break this loop */
                                break;
                            }
                        } else {
                            /* If we had an error trying to consume input, report it and cancel the query. */
                            err_str = switch_pgsql_handle_get_error(handle);
                            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
                            switch_safe_free(err_str);
                            switch_pgsql_cancel(handle);
                            goto error;
                        }
                    }
                } else if (poll_res == -1) {
                    switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll failed trying to read PGSQL socket for query (%s)\n", handle->sql);
                    goto error;
                }
            }

            /* If we broke the loop above because of a timeout, report that and cancel the query. */
            if (ctime - start > usec) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Query (%s) took too long to complete or database not responding.\n", handle->sql);
                switch_pgsql_cancel(handle);
                goto error;
            }

        }
    } else {
        /* If we had an error trying to consume input, report it and cancel the query. */
        err_str = switch_pgsql_handle_get_error(handle);
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
        switch_safe_free(err_str);
        /* switch_pgsql_cancel(handle); */
        goto error;
    }


    /* At this point, we know we can read a full result without blocking. */
    if(!(res = malloc(sizeof(switch_pgsql_result_t)))) {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Malloc failed!\n");
        goto error;
    }
    memset(res, 0, sizeof(switch_pgsql_result_t));


    res->result = PQgetResult(handle->con);
    if (res->result) {
        *result_out = res;
        res->status = PQresultStatus(res->result);
        switch(res->status) {
#if POSTGRESQL_MAJOR_VERSION >= 9 && POSTGRESQL_MINOR_VERSION >= 2
        case PGRES_SINGLE_TUPLE:
            /* Added in PostgreSQL 9.2 */
#endif
        case PGRES_TUPLES_OK:
        {
            res->rows = PQntuples(res->result);
            handle->affected_rows = res->rows;
            res->cols = PQnfields(res->result);
        }
        break;
#if POSTGRESQL_MAJOR_VERSION >= 9 && POSTGRESQL_MINOR_VERSION >= 1
        case PGRES_COPY_BOTH:
            /* Added in PostgreSQL 9.1 */
#endif
        case PGRES_COPY_OUT:
        case PGRES_COPY_IN:
        case PGRES_COMMAND_OK:
            break;
        case PGRES_EMPTY_QUERY:
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_EMPTY_QUERY\n", handle->sql);
        case PGRES_BAD_RESPONSE:
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_BAD_RESPONSE\n", handle->sql);
        case PGRES_NONFATAL_ERROR:
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_NONFATAL_ERROR\n", handle->sql);
        case PGRES_FATAL_ERROR:
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_FATAL_ERROR\n", handle->sql);
            res->err = PQresultErrorMessage(res->result);
            goto error;
            break;
        }
    } else {
        free(res);
        res = NULL;
        *result_out = NULL;
    }

    return SWITCH_PGSQL_SUCCESS;
error:

    /* Make sure the failed connection does not have any transactions marked as in progress */
    switch_pgsql_flush(handle);

    /* Try to reconnect to the DB if we were dropped */
    db_is_up(handle);

#endif
    return SWITCH_PGSQL_FAIL;
}
Пример #2
0
SWITCH_DECLARE(switch_pgsql_status_t) switch_pgsql_next_result_timed(switch_pgsql_handle_t *handle, switch_pgsql_result_t **result_out, int msec)
{
#ifdef SWITCH_HAVE_PGSQL
	switch_pgsql_result_t *res;
	switch_time_t start;
	switch_time_t ctime;
	unsigned int usec = msec * 1000;
	char *err_str;
	struct pollfd fds[2] = { {0} };
	int poll_res = 0;
	
	if(!handle) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "**BUG** Null handle passed to switch_pgsql_next_result.\n");
		return SWITCH_PGSQL_FAIL;
	}

	/* Try to consume input that might be waiting right away */
	if (PQconsumeInput(handle->con)) {
		/* And check to see if we have a full result ready for reading */
		if (PQisBusy(handle->con)) {

			/* Wait for a result to become available, up to msec milliseconds */
			start = switch_time_now();
			while((ctime = switch_micro_time_now()) - start <= usec) {
				int wait_time = (usec - (ctime - start)) / 1000;
				fds[0].fd = handle->sock;
				fds[0].events |= POLLIN;
				fds[0].events |= POLLERR;

				/* Wait for the PostgreSQL socket to be ready for data reads. */
				if ((poll_res = poll(&fds[0], 1, wait_time)) > -1 ) {
					if (fds[0].revents & POLLIN) {
						/* Then try to consume any input waiting. */
						if (PQconsumeInput(handle->con)) {
							/* And check to see if we have a full result ready for reading */
							if (!PQisBusy(handle->con)) {
								/* If we can pull a full result without blocking, then break this loop */
								break;
							}
						} else {
							/* If we had an error trying to consume input, report it and cancel the query. */
							err_str = switch_pgsql_handle_get_error(handle);
							switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
							switch_safe_free(err_str);
							switch_pgsql_cancel(handle);
							goto error;
						}
					} else if (fds[0].revents & POLLERR) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll error trying to read PGSQL socket for query (%s)\n", handle->sql);
						goto error;
					}
				} else {
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Poll failed trying to read PGSQL socket for query (%s)\n", handle->sql);
					goto error;
				}
			}

			/* If we broke the loop above because of a timeout, report that and cancel the query. */
			if (ctime - start > usec) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Query (%s) took too long to complete or database not responding.\n", handle->sql);
				switch_pgsql_cancel(handle);
				goto error;
			}



		}
	} else {
		/* If we had an error trying to consume input, report it and cancel the query. */
		err_str = switch_pgsql_handle_get_error(handle);
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "An error occurred trying to consume input for query (%s): %s\n", handle->sql, err_str);
		switch_safe_free(err_str);
		switch_pgsql_cancel(handle);
		goto error;
	}


	/* At this point, we know we can read a full result without blocking. */
	if(!(res = malloc(sizeof(switch_pgsql_result_t)))) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Malloc failed!\n");
		goto error;
	}
	memset(res, 0, sizeof(switch_pgsql_result_t));

	
	res->result = PQgetResult(handle->con);
	if (res->result) {
		*result_out = res;
		res->status = PQresultStatus(res->result);
		switch(res->status) {
		case PGRES_TUPLES_OK:
			{
				res->rows = PQntuples(res->result);
				handle->affected_rows = res->rows;
				res->cols = PQnfields(res->result);
			}
			break;
		case PGRES_COPY_OUT:
		case PGRES_COPY_IN:
		case PGRES_COMMAND_OK:
			break;
		case PGRES_EMPTY_QUERY:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_EMPTY_QUERY\n", handle->sql);
		case PGRES_BAD_RESPONSE:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_BAD_RESPONSE\n", handle->sql);
		case PGRES_NONFATAL_ERROR:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_NONFATAL_ERROR\n", handle->sql);
		case PGRES_FATAL_ERROR:
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Query (%s) returned PGRES_FATAL_ERROR\n", handle->sql);
			res->err = PQresultErrorMessage(res->result);
			goto error;
			break;
		}
	} else {
		free(res);
		res = NULL;
		*result_out = NULL;
		goto error;
	}

	return SWITCH_PGSQL_SUCCESS;
 error:
#endif
	return SWITCH_PGSQL_FAIL;
}