text:
Walk on in and see the nurse
The Rock River Valley is getting a taste of a national phenomenon — walk-in health clinics inside retail stores — at a time when the once-booming retail clinic industry is slowing and shrinking nationwide.
Take Care Health Systems, a wholly owned subsidiary of Walgreens, has opened two local clinics since May 27 as part of a steady growth that bucks the national trend.
The first local Take Care Health Clinic opened in a Rockford Walgreens. The second opened June 23 in Belvidere. Other stores in Rockford and in Roscoe are slated to open clinics by the end of the year.
Take Care's walk-in clinics are open seven days a week and staffed by board-certified family nurse practitioners who treat patients 18 months and older for common illnesses such as sore throats and urinary infections. They also administer vaccines, offer sports physicals and are licensed to write prescriptions which can be filled at a pharmacy of the patient's choice.
Each Take Care clinic has a collaborating physician with whom nurse practitioners can confer by telephone. Cases outside the scope of clinic treatment are referred to physicians, and emergency cases are sent to immediate care clinics or emergency rooms.
Walgreens puts its Take Care clinics in neighborhoods with limited access issues — "where there's not another clinic right around the corner that's open the hours we are open" — said Wendy Edwards, Take Care's lead nurse practitioner for the Rockford area.
"We're really not in competition with the immediate care clinics. We're trying to take the burden off them. A patient might go in there and just have a sore throat, when they could be seen by us instead."
Walk-in retail clinics were hailed a year ago as the latest wave in inexpensive health care for minor ailments, although retailers such as Walgreens and CVS Caremark have been criticized because their clinics rely on nurse practitioners rather than physicians.
A plan to install Medical Mart physician-staffed walk-in clinics at two Rockford-area Kmart stores last November went by the boards when Medical Mart, a privately backed company based in Las Vegas, went out of business.
The demise was part of a larger fallout after aggressive retail clinic growth that mimicked the dot-com boom, said Tom Charland, CEO of Minnesota-based industry research firm Merchant Medicine. "We saw a lot of irrationality, people getting into the retail clinic business thinking if they opened, people would come."
The number of retail clinics nationwide nearly quadrupled from 202 to 710 in the year between October 2006 and 2007. Then industry growth slowed.
By April 2008, the total had only reached 964. And many of the privately backed retail clinic companies — such as Medical Mart and My Healthy Access which had clinics in some Wal Mart stores — had gone bust.
It was all about the money, Charland said.
"Many of the new operators were getting funding from private investors before they had a business model, so they were burning cash." Charland said. "The interest of their investors was in making money."
Retailers such as Walgreens with its Take Care clinics and CVS with its MinuteClinics take a more long-term view, he said.
"The clinic is a destination, so there are new people coming into their stores who wouldn't be there otherwise," Charland said. "And about 25 percent of those patients represent new prescription customers. Even if you haven't hit break-even (with the clinics), you still have this other benefit going on."
Even industry leader CVS, which has grown aggressively, cut its MinuteClinic locations from 513 in April to 511 by late June and has announced it is scaling back growth plans, according to Merchant Medicine data.
Walgreens grew its Take Care locations from 158 to 183 during that same time, and said in late June it was on track for 400 clinics by year's end.
Walgreens does not divulge its costs of building a Take Care clinic, but does expect each new clinic to take two or three years to turn a profit, Take Care Health Systems spokeswoman Lauren Tierney said.
"That's not an unusual time frame," she said. "When we open a new drugstore, there's also a typical two- to three-year period before the store turns profitable."
That long-term approach seems to prevail at the Rockford Take Care clinic as well. It has seen about 50 patients in the month since its opening, an average of one or two a day, Edwards said. "We're really doing better than expected," she said.
The clinics advertise and send direct-mail pieces to their surrounding neighborhoods, but most patients come by word-of-mouth, Edwards said.
Take Care started locally with a staff of eight nurse practitioners when it opened its Rockford store. Edwards anticipates raising that total to 12 by mid-July to cover the Rockford and Belvidere locations.
The local clinics also are compiling a growing list of local physicians to whom they can refer patients who need primary care physicians or specialists.
Nurse practitioners for the Rockford clinic have a list of 10 such physicians so far, Edwards said. They are canvassing the Belvidere area to start a similar list, she said.
For more information visit takecarehealth.com and merchantmedicine.com.
Deborah Austin can be reached at (815) 987-1352 or at firstname.lastname@example.com
Take Care Health Clinic Q&A
Where are the Take Care Health Clinics in the Rock River Valley?
Inside the Walgreens stores at 3336 11th St., Rockford, and 230 W. Chrysler Drive, Belvidere.
What hours are the clinics open?
8 a.m. to 7:30 p.m. Monday through Friday, and 9 a.m. to 4:30 p.m. Saturday and Sunday
Do I call ahead for an appointment?
No, patients are taken on a walk-in basis.
Do they take insurance?
Take Care clinics in the Rockford area accept insurance with many major companies including Aetna, Blue Cross/Blue Shield, ChoiceCare, Humana, Medicare, Medicaid and others. Information is available at each clinic.
What will it cost me if I don't have insurance coverage?
A typical visit including an exam costs between $59 and $74. Some tests, such as a $10 pregnancy test, would be in addition to that cost, while others could be included in your visit cost. Sports and camp physicals are a flat $25.
If you are getting a vaccine, typically there is no visit charge. You are charged only for the vaccine.
Vaccination prices include:
Hepatitis B $64
Influenza $24.99
Meningitis (Menactra) $110
Tetanus booster $45
Tetanus-pertussis booster $65
How do I pay?
With cash, credit card or debit card. Personal checks are not accepted.
Will I see a doctor?
Not at the clinic. Take Care clinics are staffed by nurse practitioners, who have graduate degrees in advanced practice nursing. Nurse practitioners are licensed to provide such services as performing a physical exam, ordering lab tests, diagnosing and treating diseases and writing prescriptions.
The clinics also have a collaborating physician, whom the nurse practitioner can call anytime during clinic hours if he or she needs to collaborate on your case.
What happens when I get there?
You enter your personal information into a touch screen kiosk at the entrance to the clinic. Information entered includes your name, phone number, birth date, the condition for which you want treatment, and whether you prefer to self-pay or submit your costs to an insurance company.
The nurse practitioner greets you, guides you to an exam room and takes your insurance information, medical history and information about emergency contacts and your primary care physician. The information is entered electronically into the clinic's computer system.
How big are the clinics and what's there?
The 260-square-foot clinics are located next to the stores' pharmacies and share a waiting area with the pharmacies. Each clinic has two patient exam rooms with examination tables, sinks, and equipment to take vital signs such as blood pressures and temperature.
What if there's a waiting line and I'm not feeling well?
Once you have signed in on the kiosk, your place is held in line. If the nurse practitioner sees there will be a wait, he or she may ask for your cell phone number and call you to come back when your turn is getting close.
At this point, the Take Care clinics in the Rock River Valley area are so new that there have not been waiting lines, said Wendy Edwards, Take Care's lead nurse practitioner for the Rockford area.
What kinds of conditions do Take Care clinics generally treat?
Conditions treated include bronchitis, ear infections, strep throat, sinus infections, urinary infections, allergies, poison ivy and poison oak, skin infections and insect bites.
The clinics also offer vaccinations such as tetanus, hepatitis B and meningitis.
You can see a more complete list of treated conditions at takecarehealth.com/treat.htm.
How long does a visit usually take?
Visits typically take about 20 minutes.
What if my condition is beyond the scope of what can be treated at the clinic?
If you need to see a physician, you will be referred back to your primary care physician for care. If you don't have a primary care physician, clinic staff will offer you a list of physicians in the area who are taking new patients.
If your condition is an emergency you will be sent to the nearest urgent care clinic or emergency room, depending on the severity of your situation. If necessary, clinic staff will call 911.
Do I have to get my Take Care prescription filled at Walgreens?
Your prescription can be sent electronically to any pharmacy of your choice. You don't need to fill it at Walgreens unless you want to.
Can I take records of my clinic visit to my own doctor?
Yes, you can take a record of your Take Care visit with you. It will give your doctor information about your condition and the history of your treatment at the clinic.
What if I go to a Take Care clinic somewhere else, will they have my records?
Your can ask any Take Care Health Clinic throughout the country to access your records electronically.
For more information see takecarehealth.com.
Sources: takecarehealth.com; Wendy Edwards, Take Care's lead nurse practitioner for the Rockford area; National Institutes of Health.


text:
In our world we see people doing all kinds of evil things in the name of their religion. On a daily basis we hear of people being beheaded, persecuted and murdered by all kinds of vile methods for not converting to radical Islam. People trying to force another by violence to adhere to their twisted ideology. Amid all of this, I am so grateful that we who are followers of Jesus Christ serve a Savior and Lord that does not require that we use violence to draw people to Him. He requires love! How awesome is He! He tells us to let our light shine, He tells us to let the world see His love for them through us! He tells us that when we feed the hungry, clothe the naked, heal the sick and give water to the thirsty we are doing it to Him! Matthew 25:31-40 NIV 31 "When the Son of Man comes in his glory, and all the angels with him, he will sit on his glorious throne. 32 All the nations will be gathered before him, and he will separate the people one from another as a shepherd separates the sheep from the goats. 33 He will put the sheep on his right and the goats on his left.34 "Then the King will say to those on his right, 'Come, you who are blessed by my Father; take your inheritance, the kingdom prepared for you since the creation of the world. 35 For I was hungry and you gave me something to eat, I was thirsty and you gave me something to drink, I was a stranger and you invited me in, 36 I needed clothes and you clothed me, I was sick and you looked after me, I was in prison and you came to visit me.' 37 "Then the righteous will answer him, 'Lord, when did we see you hungry and feed you, or thirsty and give you something to drink? 38 When did we see you a stranger and invite you in, or needing clothes and clothe you? 39 When did we see you sick or in prison and go to visit you?' 40 "The King will reply, 'Truly I tell you, whatever you did for one of the least of these brothers and sisters of mine, you did for me.'
In the book of Mark we see our beautiful Lord and King healing the leper after being moved with compassion. Mark 1:39-42 NKJV 39 And He was preaching in their synagogues throughout all Galilee, and casting out demons.40 Now a leper came to Him, imploring Him, kneeling down to Him and saying to Him, "If You are willing, You can make me clean." 41 Then Jesus, moved with compassion, stretched out His hand and touched him, and said to him, "I am willing; be cleansed." 42 As soon as He had spoken, immediately the leprosy left him, and he was cleansed.
Jesus, the Son of God, the Holy One, the King of Kings was moved with compassion! What a beautiful picture of our Jesus! A King who feels for the cast offs of society and is moved to save, heal and deliver them! A King who does not see class distinction. A King who does not wish any should spiritually perish! A King that is moved with compassion!
Today let the reality of the character of Jesus sink into your heart. Ask Him to give you a heart of compassion for those who are lost, sick and bound. Ask Him to guide you in reaching out and sharing the good news with those who so desperately need to hear it! Let His love and compassion shine through you this Christmas season!

subset: commoncrawl


text:
Panasonic Technology Solutions for Healthcare Businesses
Set new standards of healthcare with proven solutions
When lives are on the line, you need to know you can count on your technology. Our proven healthcare technology solutions are already used in hospitals, medical practices and care homes, helping them deliver better standards of care and superior living and working environments.
Our healthcare computing solutions, microscopy camera technology, communications systems, interactive displays, projectors, hospital CCTV and surveillance equipment are all backed by consultancy, project management and support services.
And with expertise in areas such as IOT solutions and digitisation, you get the very best connected technology solutions, freeing you to deliver the very best care and treatment.


text:
Well, it's been an interesting journey from around 2004 when the LIPS – Leaders in Public Schools concept kicked off as an email listserv which sought to emulate the sharing which had been seen on the NSW Primary Principals' Association PASHN (Principals' Association Self Help Network) which had been set up in Nov 2002. (Trove & iNet Online)
Along the way, a blog format was seen as a better way to go and the blog has been used to post all sorts of things which have hopefully been of use to educators and others along the way.
A healthy aspect of our ability to post ideas is that not everybody will agree, and it has been good sometimes to see some spirited exchanges of ideas in the comments and elsewhere.
Now, as we enter 2012, almost 10 years since the launch of PASHN, and after a number of roles within Public Education, and some of the evolution which occurs as a natural consequence of time, it seems a good time to draw this blog to a close.
You can still access it here, and I hope that you might still enjoy some of the posts. I will continue to promote concepts like the need to move from 'School Planning' to 'Planning School' and certainly the efficacy of an approach which is 'Tight, Loose, Tight.'
I'd also suggest that you look for some new ideas at the EDULEADER BLOG and in the news and updates section of HCCWEB2.ORG
If you're interested in keeping track of what I'm up to you can also check out my main web portal page at PRYORCOMMITMENT.COM and follow the various links from there to writing and thoughts at PEBBLES IN THE POOL.
You can also follow me on Twitter or check out my profile on LinkedIN
But, for now, these LIPS are sealed.
Leave a Reply
You must be logged in to post a comment.


text:
Top Five Books Santa Didn't Bring
It's the curse of the bookish: no one buys you books for Christmas because no one knows what to get you. This is the first year I haven't received even a gift certificate though! Luckily, I'm taking part in a secret Santa with my fellow Edmonton book bloggers next week. Here's my wish list:
- Crazy Rich Asians by Kevin Kwan because it's shiny.
- Tampa by Alissa Nutting because it's fuzzy, though must give a shout out to that paperback cover!!
- Omens by Kelley Armstrong because crows creep me out so much but this cover calls to me.
- Christmas Stories edited by Diana Secker Tesdell because it out Goldfinches The Goldfinch. Also just realized Tesdell has edited a whole bunch of these collections and I want them all!
- War and Peace by Leo Tolstoy because I need a classic in here, and I think it might be time… I hear rumblings about a readalong and Norm's Book Club keeps tweeting about it.
I hope you all got what you want for Christmas!


text:
Read More: See the debut trailer and screenshots.
Bethesda Japan has gone live with first story details and a list of key features for Tango Gameworks' newly revealed survival horror game The Evil Within (or Psychobreak as it's called in Japan) ahead of Monday's IGN details story.
The game, which uses the latest version of the id Tech 5 engine, is detailed below.
When Detective Sebastian and his partner rush to the scene of a gruesome mass murder, a mysterious, powerful force is lying in wait for them. Witnessing the killing of fellow police officers one after another, Sebastian is then attacked and loses consciousness. Waking up in a land where monsters are wandering about, Sebastian has to fight his way through a world of death and its close friend madness in order to understand what's going on. Sebastian has to face his fears in order to survive on a journey to discover what lies in the shadows of that mysterious force.
Key Features
- A Return to Pure Survival Horror: From the father of the survival horror genre, Shinji Mikami. He appears once again as the director of this game, one which makes your blood run cold, but heats you right back up. Players must survive on limited resources, experiencing that supreme match of action and horror, that indescribable terror. To survive in an afflicted world, your anxiety and nerves will be pushed to the edge.
- Brutal Traps and Enemies with Puzzles: While struggling to survive, you'll have to face indescribable terror, cruel traps, and sly mechanisms. Players can die in a trap all too easily, however, at times they can turn them against enemies.
- In an Unstable World, Not All Horrors are in Plain Sight: The player is driven into a corner as the world distorts and warps according to mysterious and evil horrors. The scenery: hallways, walls, doors, rooms, buildings, and even nature, all transforming in real time based on the player's actions. And the threats keep coming from all directions.
- A Supernova of Horror: By setting one foot in this world weaved from lush backdrops, characters with personality, and a polished story, players will be sucked in, willing or unwilling, tension and anxiety rapidly mounting. When that fear is smashed and conquered, you can experience the bliss that can only be found in The Evil Within.


text:
Google has added a new notification to its Cloud Storage service, allowing applications to automatically take action when new content is uploaded by users.
Normally, applications would have to poll for changes, which can be a resource waste or cause the application to react slowly. Also, writing and deploying custom scripts to trigger an application is cumbersome for developers, Google said in a blog post. But the object change notification will change that and seemingly make life a little easier for developers.
The notification is used to monitor Google Cloud Storage buckets for new, modified or deleted objects. For example, when a users adds a new picture to a bucket, an application could be notified to automatically create a thumbnail. The application and the bucket communicate using a so-called notification channel. A website detailing the feature shows how to add one.
The object change notification is only a preview feature. That means it is still being developed and Google can make backwards-incompatible changes, it warned.
Google is also releasing an updated version of its Cloud Storage JSON API (application programming interface), bringing it into parity with the existing XML API. The JSON API is now available to everyone, as well.
Google's cloud team is now getting ready for the I/O conference. It will take place at the Moscone Center in San Francisco between May 15 and May 17. While Google's cloud services may not get as much attention as Android and the company's consumer services, there is a separate track entitled "Google Cloud Platform." As part of the track, visitors will get a chance to learn more about how Web-based mobile applications can take advantage of the cloud and there are also a number of sessions on various aspects of using BigQuery, which Google has been upgrading to better handle big data applications.


text:
Opinionators are offering a number of explanations for Virginia Thomas's bizarro phone call to Anita Hill: love, innocence, naivete, Ambien. Are we, um, dancing around something here?
On Tuesday, Gawker's Max Read opined that maybe Thomas asked Hill for an apology nineteen years after the fact because she "was wasted at 7:30 a.m. on a Saturday and got to drunk-dialing." Journalist Karen Hunter said, "It'll probably come out that she was in an Ambien stupor — or maybe she's taping a reality TV show." So basically, Thomas was behaving like someone whose judgment was impaired.
Slate's Dahlia Lithwick extends a more complex theory:
My friend Nancy Goldstein wonders if this was meant to distract from a New York Times story that ran the same day as the fateful phone call, questioning Ginni Thomas' 501(c)(4) organization, Liberty Central. Perhaps, although it's difficult to imagine Ms. Thomas delivering a blistering Tea Party speech on a Friday night, opening her New York Times the next morning, and thinking, "Hey, maybe I'll call Anita Hill right this instant." Moreover, as Goldstein notes, if this was intended to distract from the conflicts around Liberty Central, it didn't work, since Hill sat on the message for several days.
Right, so her plans are strange, and they don't work.
Jacob Bernstein of The Daily Beast talked to Thomas's brother, who said of Hill's sexual harassment allegations, "I don't believe it needs to be in the press in any shape or form. It was very difficult for my mother and father who are now passed away, and I'm sorry that Ginni decided to talk more about it." He also talked to her aunt, who said only, "I'm confused." Thomas's actions don't make sense, even to her own family.
But was the call merely a brief lapse by an otherwise sensible person? Says her former boss Hal Daub,
I think what was in her heart was an attempt to see if there could be some healing. Maybe today she might think better of that outreach, but that phone call strikes me as very Ginni Lamp Thomas. It seems perfectly normal.
Bernstein also notes that Thomas used to be involved with the New Age group Lifespring, which some have called a cult, and that "her history with the group led some to view her as a bit of a flake." He also quotes Thomas's former minister:
There's a kind of naivete about her, a kind of innocence you have to be careful with. Ginni is a very, very trusting person — she once invited a homeless man out to lunch with her in a fancy Washington restaurant...I'm sure that's one of the reasons she was very susceptible to this group. She was looking for spiritual growth and trusted those people would do the right thing.
So Ginni Thomas is innocent, naive, overly trusting, and prone to doing confusing things without thinking them through. Let's come right out and say it: maybe she's just stupid.
Why Clarence's Wife Called Anita [Daily Beast]
Would You Like To Leave A Message? [Slate]
Clarence Thomas' Wife Calls Anita Hill To Ask For an Apology [Gawker]
Why Did Virginia Thomas Call Anita Hill After All This Time? [Politics Daily]
Earlier: Clarence Thomas's Wife Leaves Ridiculous Voicemail For Anita Hill


text:
Kentucky hires FSU assistant Stoops as coach
LEXINGTON, Ky. — Kentucky has found its new football coach.
The Wildcats announced Tuesday that they have hired Florida State defensive coordinator Mark Stoops to coach the Wildcats.
Stoops replaces Joker Phillips, who was fired on Nov. 4. Phillips went 13-24 in three seasons at Kentucky. The Wildcats were 0-8 in the Southeastern Conference this year.
The 45-year-old Stoops will be introduced here at a news conference on Sunday. No. 13 Florida State (10-2) plays Georgia Tech Saturday in the Atlantic Coast Conference championship game.
His hiring concludes a quicker-than-expected coaching search for the university. After Saturday's season-ending loss at Tennessee, Kentucky athletic director Mitch Barnhart said he had no timetable to find a replacement for Phillips.
But it didn't take long for Barnhart and the Wildcats to make a move. The decision makes Stoops a head coach for the first time in his career.
"I want to thank (Kentucky) President Eli Capilouto and Mitch Barnhart for this opportunity," Stoops said in a statement. "I promise the faithful of the Big Blue Nation I will be focused and driven to create a positive, winning atmosphere for the program and an environment that all of Kentucky can be proud of."
Stoops becomes the third brother in college football's famed coaching family to lead his own program. Older brother Bob Stoops is the head coach at Oklahoma and Mike Stoops is the Sooners' defensive coordinator. Before joining the Oklahoma staff this year, Mike was the head coach at Arizona.
Mark Stoops has been the Seminoles' defensive coordinator the past three seasons. Florida State's defense was ranked 108th when he took over and he has turned the Seminoles into one of the nation's top defensive teams.
The Seminoles have the nation's second-ranked defense, giving up 249.4 yards per game. Kentucky allowed 391 yards a contest this season.
"Our desire to get better defensively and continue to expand our recruiting base helped guide us to Mark," Barnhart said. "He comes from a coaching family and has been in big games and big atmospheres throughout his career."


text:
|Oracle® Call Interface Programmer's Guide,
11g Release 1 (11.1)
Part Number B28395-01
|View PDF
This chapter contains these topics:
The OCI datatype mapping and manipulation functions provide the ability to manipulate instances of predefined Oracle C datatypes. These datatypes are used to represent the attributes of user-defined datatypes, including object types in Oracle.
Each group of functions within the OCI is distinguished by a particular naming convention. The datatype mapping and manipulation functions, for example, can be easily recognized because the function names start with the prefix OCI, followed by the name of a datatype, as in
OCIDateFromText() and
OCIRawSize(). As will be explained later, the names can be further broken down into function groups that operate on a particular type of data.
Additionally, the predefined Oracle C types on which these functions operate are also distinguished by names which begin with the prefix OCI, as in
OCIDate or
The datatype mapping and manipulation functions are used when an application needs to manipulate, bind, or define attributes of objects that are stored in an Oracle database, or which have been retrieved by a SQL query. Retrieved objects are stored in the client-side object cache, and described in Chapter 14, "Object Advanced Topics in OCI".
This chapter describes the purpose and structure of each of the datatypes that can be manipulated by the OCI datatype mapping and manipulation functions. It also summarizes the different function groups, and gives lists of available functions and their purposes.
This chapter also provides information about how to use these datatypes in bind and define operations within an OCI application.
The OCI client must allocate a descriptor before bind or define is done.
OCIStmtExecute() and
OCIStmtFetch2() will not allocate the memory for the descriptors if they are not allocated by
These functions are valid only when an OCI application is running in object mode. For information about initializing the OCI in object mode, and creating an OCI application that accesses and manipulates objects, refer to the section "Initializing Environment and Object Cache".
See Also:For detailed information about object types, attributes, and collection datatypes, refer to Oracle Database Concepts.
Note:Operations on object types such as
OCIDate, and so on, allow the address of the result to be the same as that of one of the operands.
Oracle provides a rich set of predefined datatypes with which you can create tables and specify user-defined datatypes (including object types). Object types extend the functionality of Oracle by allowing you to create datatypes that precisely model the types of data with which they work. This can provide increased efficiency and ease-of-use for programmers who are accessing the data.
NCHAR and NVARCHAR2 can be used as attributes in objects and map to
OCIString * in C.
Database tables and object types are based upon the datatypes supplied by Oracle. These tables and types are created with SQL statements and stored using a specific set of Oracle internal datatypes, like
VARCHAR2 or
NUMBER. For example, the following SQL statements create a user-defined
address datatype and an object table to store instances of that type:
CREATE TYPE address AS OBJECT (street1 varchar2(50), street2 varchar2(50), city varchar2(30), state char(2), zip number(5)); CREATE TABLE address_table OF address;
The new
address type could also be used to create a regular table with an object column:
CREATE TABLE employees (name varchar2(30), birthday date, home_addr address);
An OCI application can manipulate information in the
name and
birthday columns of the
employees table using straightforward bind and define operations in association with SQL statements. Accessing information stored as attributes of objects requires some extra steps.
The OCI application first needs a way to represent the objects in a C-language format. This is accomplished by using the Object Type Translator (OTT) to generate C struct representations of user-defined types. The elements of these structs have datatypes that represent C language mappings of Oracle datatypes.
See Also:Table 15-1, "Object Datatype Mappings for Object Type Attributes" for the available Oracle types you can use as object attribute types and their C mappings
An additional C type,
OCIInd, is used to represent null indicator information corresponding to attributes of object types.
See Also:For more information and examples regarding the use of the OTT, refer to Chapter 15, "Using the Object Type Translator with OCI".
Oracle followed a distinct design philosophy when specifying the mappings of Oracle predefined types. The current system has the following benefits and advantages:
The actual representation of datatypes like
OCINumber is opaque to client applications, and the datatypes are manipulated with a set of predefined functions. This allows for the internal representation to change to accommodate future enhancements without breaking user code.
The implementation is consistent with object-oriented paradigms in which class implementation is hidden and only the required operations are exposed.
This implementation can have advantages for programmers. Consider a C program that wants to manipulate Oracle number variables without losing the accuracy provided by Oracle numbers. To do this in Oracle release 7, you would have had to issue a "
SELECT ... FROM DUAL" statement. In later releases, this is accomplished by invoking the
OCINumber*() functions
In an OCI application, the manipulation of data may be as simple as adding together two integer variables and storing the result in a third variable:
int int_1, int_2, sum; ... /* some initialization occurs */ ... sum = int_1 + int_2;
The C language provides a set of predefined operations on simple types like
integer. However, the C datatypes listed in Table 15-1, "Object Datatype Mappings for Object Type Attributes" are not simple C primitives. Types like
OCIString and
OCINumber are actually structs with a specific Oracle-defined internal structure. It is not possible to simply add together two
OCINumbers and store the value in the third.
The following is not valid:
OCINumber num_1, num_2, sum; ... /* some initialization occurs */ ... sum = num_1 + num_2; /* NOT A VALID OPERATION */
The OCI datatype mapping and manipulation functions are provided to enable you to perform operations on these new datatypes. For example, the preceding addition of
OCINumbers could be accomplished as follows, using the
OCINumberAdd() function:
OCINumber num_1, num_2, sum; ... /* some initialization occurs */ ... OCINumberAdd(errhp, &num_1, &num_2, &sum): /* errhp is error handle */
The OCI provides functions to operate on each of the new datatypes. The names of the functions provide information about the datatype on which they operate. The first three letters, OCI, indicate that the function is part of the OCI. The next part of the name indicates the datatype on which the function operates. The following table shows the various function prefixes, along with example function names and the datatype on which those functions operate:
Table 12-1 Function Prefix examples
|Function Prefix
|Operates On
OCIColl, OCIIter, OCITable, OCIArray
OCIDate, OCIDateTime
OCIRaw *
OCIRef *
OCIString *
OCITable *
The structure of each of the datatypes is described later in this chapter, along with a list of the functions that manipulate that type.
Oracle numbers have a precision of 38 decimal digits. All Oracle number operations are accurate to the full precision, with the following exceptions:
Inverse trigonometric functions are accurate to 28 decimal digits.
Other transcendental functions, including trigonometric functions, are accurate to approximately 37 decimal digits.
Conversions to and from native floating-point types have the precision of the relevant floating-point type, not to exceed 38 decimal digits.
The Oracle date format is mapped in C by the
OCIDate type, which is an opaque C struct. Elements of the struct represent the year, month, day, hour, minute, and second of the date. The specific elements can be set and retrieved using the appropriate OCI functions.
OCIDate datatype can be bound or defined directly using the external typecode
SQLT_ODT in the bind or define call.
Unless otherwise specified, the term date in these function calls refers to a value of type
See Also:The prototypes and descriptions for all the functions are provided in Chapter 19, "OCI Datatype Mapping and Manipulation Functions".
The following code provides examples of how to manipulate an attribute of type
OCIDate using OCI calls. For this example, assume that
OCIEnv and
OCIError have been initialized as described in Chapter 2, "OCI Programming Basics". See Chapter 14, "Object Advanced Topics in OCI" for information about pinning.
#define FMT "DAY, MONTH DD, YYYY" #define LANG "American" struct person { OCIDate start_date; }; typedef struct person person; OCIError *err; person *tim; sword status; /* error status */ uword invalid; OCIDate last_day, next_day; text buf[100], last_day_buf[100], next_day_buf[100]; ub4 buflen = sizeof(buf); /* Pin tim person object in the object cache. */ /* For this example, assume that /* tim is pointing to the pinned object. */ /* set the start date of tim */ OCIDateSetTime(&tim->start_date,8,0,0); OCIDateSetDate(&tim->start_date,1990,10,5); /* check if the date is valid */ if (OCIDateCheck(err, &tim->start_date, &invalid) != OCI_SUCCESS) /* error handling code */ if (invalid) /* error handling code */ /* get the last day of start_date's month */ if (OCIDateLastDay(err, &tim->start_date, &last_day) != OCI_SUCCESS) /* error handling code */ /* get date of next named day */ if (OCIDateNextDay(err, &tim->start_date, "Wednesday", strlen("Wednesday"), &next_day) != OCI_SUCCESS) /* error handling code */ /* convert dates to strings and print the information out */ /* first convert the date itself*/ buflen = sizeof(buf); if (OCIDateToText(err, &tim->start_date, FMT, sizeof(FMT)-1, LANG, sizeof(LANG)-1, &buflen, buf) != OCI_SUCCESS) /* error handling code */ /* now the last day of the month */ buflen = sizeof(last_day_buf); if (OCIDateToText(err, &last_day, FMT, sizeof(FMT)-1, LANG, sizeof(LANG)-1, &buflen, last_day_buf) != OCI_SUCCESS) /* error handling code */ /* now the first Wednesday after this date */ buflen = sizeof(next_day_buf); if (OCIDateToText(err, &next_day, FMT, sizeof(FMT)-1, LANG, sizeof(LANG)-1, &buflen, next_day_buf) != OCI_SUCCESS) /* error handling code */ /* print out the info */ printf("For: %s\n", buf); printf("The last day of the month is: %s\n", last_day_buf); printf("The next Wednesday is: %s\n", next_day_buf);
The output will be:
For: FRIDAY , OCTOBER 05, 1990 The last day of the month is: WEDNESDAY, OCTOBER 31, 1990 The next Wednesday is: WEDNESDAY, OCTOBER 10, 1990
OCIDateTime datatype is an opaque structure used to represent Oracle time and timestamp datatypes (
ZONE) and the
ANSI DATE datatype. You can set or retrieve the data in these types (that is, year, day, fractional second) using the appropriate OCI functions.
OCIInterval datatype is also an opaque structure and is used to represent Oracle interval datatypes (
You can bind and define
OCIDateTime and
OCIInterval data using the following external typecodes in the bind or define call:
Table 12-2 Binding and Defining Datetime and Interval Datatypes
|OCI Datatype
|Type of Data
|External Typecode for Binding/Defining
The OCI functions which operate on datetime and interval data are listed in the following tables. More detailed information about these functions can be found in OCI Date, Datetime, and Interval Functions.
In general, functions which operate on
OCIDateTime data are also valid for
OCIDate data.
The following functions operate on
OCIDateTime values. Some of these functions also perform arithmetic operations on datetime and interval values. Some functions may only work for certain datetime types. The possible types are:
See the individual function descriptions for more information about input types which are valid for a particular function.
Table 12-3 Datetime Functions
Performs datetime assignment
Checks if the given date is valid
Compares two datetime values
Constructs a datetime descriptor
Converts one datetime type to another
Converts an array of size
Converts the given string to Oracle datetime type in the
Gets the date (year, month, day) portion of a datetime value
Gets the time (hour, minute, second, fractional second) out of a datetime value
Gets the time zone name portion of a datetime value
Gets the time zone (hour, minute) portion of a datetime value
Adds an interval to a datetime to produce a resulting datetime
Subtracts an interval from a datetime and stores the result in a datetime
Takes two datetimes as input and stores their difference in an interval
Gets the system current date and time as a timestamp with time zone
Converts a OCIDateTime descriptor to an array
Converts the given date to a string according to the specified format
Converts date from one time zone to another zone
The following snippet of code shows how to use an
OCIDateTime datatype to select data from a
TIMESTAMP WITH LOCAL TIME ZONE column:
... /* allocate the program variable for storing the data */ OCIDateTime *tstmpltz = (OCIDateTime *)NULL; /* Col1 is a timestamp with local time zone column */ OraText *sqlstmt = (OraText *)"SELECT col1 FROM foo"; /* Allocate the descriptor (storage) for the datatype */ status = OCIDescriptorAlloc(envhp,(void **)&tstmpltz, OCI_DTYPE_TIMESTAMP_LTZ, 0, (void **)0); .... status = OCIStmtPrepare (stmthp, errhp, sqlstmt, (ub4)strlen ((char *)sqlstmt), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT); /* specify the define buffer for col1 */ status = OCIDefineByPos(stmthp, &defnp, errhp, 1, &tstmpltz, sizeof(tstmpltz), SQLT_TIMESTAMP_LTZ, 0, 0, 0, OCI_DEFAULT); /* Execute and Fetch */ OCIStmtExecute(svchp, stmthp, errhp, 1, 0,(OCISnapshot *) NULL, (OCISnapshot *)NULL, OCI_DEFAULT) At this point tstmpltz contains a valid timestamp with local time zone data. You can get the time zone name of the datetime data using: status = OCIDateTimeGetTimeZoneName(envhp, errhp, tstmpltz, (ub1 *)buf, (ub4 *)&buflen); ...
The following functions operate exclusively on interval data. In some cases it is necessary to specify the type of interval involved. Possible types include:
SQLT_INTERVAL_YM - interval year to month
SQLT_INTERVAL_DS - interval day to second
See the individual function descriptions for more detailed information.
See Also:Complete lists of the names and purposes as well as more detailed information about these functions can be found in OCI Date, Datetime, and Interval Functions.
Table 12-4 Interval Functions
OCIIterCreate() (UNKNOWN STEP NUMBER)
Adds two intervals to produce a resulting interval
OCIIntervalAssign() (UNKNOWN STEP NUMBER)
Copies one interval to another
Checks the validity of an interval
Compares two intervals
Divides an interval by an Oracle Number to produce an interval
Converts an Oracle Number to an interval
Given an interval string, produces the interval represented by the string
Gets values of day and second from an interval
Gets year and month from an interval
Multiplies an interval by an Oracle Number to produce an interval
Sets day and second in an interval
Sets year and month in an interval
Subtracts two intervals and stores the result in an interval
Converts an interval to an Oracle Number
Given an interval, produces a string representing the interval
OCINumber datatype is an opaque structure used to represent Oracle numeric datatypes (
DECIMAL, and so forth). You can bind or define this type using the external typecode
SQLT_VNU in the bind or define call.
Unless otherwise specified, the term number in these functions refers to a value of type
See Also:The prototypes and descriptions for all the functions are provided in Chapter 19, "OCI Datatype Mapping and Manipulation Functions".
The following two snippets show how to manipulate an attribute of type
OCINumber. The second snippet shows how to convert values in
OCINumber format returned from
OCIDescribeAny() calls to unsigned integers.
/* Example 1 */ struct person { OCINumber sal; }; typedef struct person person; OCIError *err; person* steve; person* scott; person* jason; OCINumber *stevesal; OCINumber *scottsal; OCINumber *debsal; sword status; int inum; double dnum; OCINumber ornum; text buffer[21]; ub4 buflen; sword result; /* For this example, assume OCIEnv and OCIError are initialized. */ /* For this example, assume that steve, scott and jason are pointing to person objects which have been pinned in the object cache. */ stevesal = &steve->sal; scottsal = &scott->sal; debsal = &jason->sal; /* initialize steve's salary to be $12,000 */ inum = 12000; status = OCINumberFromInt(err, &inum, sizeof(inum), OCI_NUMBER_SIGNED, stevesal); if (status != OCI_SUCCESS) /* handle error from OCINumberFromInt */; /* initialize scott's salary to be same as steve's */ OCINumberAssign(err, stevesal, scottsal); /* initialize jason's salary to be 20% more than steve's */ dnum = 1.2; status = OCINumberFromReal(err, &dnum, sizeof(dnum), &ornum); if (status != OCI_SUCCESS) /* handle error from OCINumberFromReal */; status = OCINumberMul(err, stevesal, &ornum, debsal); if (status != OCI_SUCCESS) /* handle error from OCINumberMul */; /* give scott a 50% raise */ dnum = 1.5; status = OCINumberFromReal(err, &dnum, sizeof(dnum), &ornum); if (status != OCI_SUCCESS) /* handle error from OCINumberFromReal */; status = OCINumberMul(err, scottsal, &ornum, scottsal); if (status != OCI_SUCCESS) /* handle error from OCINumberMul */; /* double steve's salary */ status = OCINumberAdd(err, stevesal, stevesal, stevesal); if (status != OCI_SUCCESS) /* handle error from OCINumberAdd */; /* get steve's salary in integer */ status = OCINumberToInt(err, stevesal, sizeof(inum), OCI_NUMBER_SIGNED, &inum); if (status != OCI_SUCCESS) /* handle error from OCINumberToInt */; /* inum is set to 24000 */ /* get jason's salary in double */ status = OCINumberToReal(err, debsal, sizeof(dnum), &dnum); if (status != OCI_SUCCESS) /* handle error from OCINumberToReal */; /* dnum is set to 14400 */ /* print scott's salary as DEM0001'8000.00 */ buflen = sizeof(buffer); status = OCINumberToText(err, scottsal, (text *)"C0999G9999D99", 13, (text *)"NLS_NUMERIC_CHARACTERS='.'' NLS_ISO_CURRENCY='Germany'", 54, &buflen, (text *)buffer); if (status != OCI_SUCCESS) /* handle error from OCINumberToText */; printf("scott's salary = %s\n", buffer); /* compare steve and scott's salaries */ status = OCINumberCmp(err, stevesal, scottsal, &result); if (status != OCI_SUCCESS) /* handle error from OCINumberCmp */; /* result is positive */ /* read jason's new salary from string */ status = OCINumberFromText(err, (text *)"48'000.00", 9, (text *)"99G999D99", 9, (text *)"NLS_NUMERIC_CHARACTERS='.''", 27, debsal); if (status != OCI_SUCCESS) /* handle error from OCINumberFromText */; /* jason's salary is now 48000.00 */
Here is an example of how to convert a numeric type returned from an
OCIDescribeAny() call in
OCINumber format, such as
OCI_ATTR_MAX or
OCI_ATTR_MIN, to an unsigned C integer:
/* Example 2 */ ub4 max_seq_val = 0; ub1 *max_valp = NULL; ub4 max_val_size; OCINumber max_val; OCINumberSetZero(_errhp, &max_val); OCIParam* parmdp = 0; status = OCIAttrGet ((void *)_dschp, (ub4)OCI_HTYPE_DESCRIBE, &parmdp, 0, (ub4)OCI_ATTR_PARAM, _errhp); if (isError (status, _errhp)) { return 0; } status = OCIAttrGet ((void *)parmdp, (ub4)OCI_DTYPE_PARAM, &max_valp, &max_val_size, (ub4)OCI_ATTR_MAX, _errhp); //create an OCINumber object from the ORACLE NUMBER FORMAT max_val.OCINumberPart[0] = max_val_size; //set the length byte memcpy(&max_val.OCINumberPart[1], max_valp, max_val_size); //copy the actual bytes //now convert max_val to an unsigned C integer, max_seq_val status = OCINumberToInt(_errhp, &max_val, sizeof(max_seq_val), OCI_NUMBER_UNSIGNED, &max_seq_val);
Fixed or variable-length string data is represented to C programs as an
OCIString *.
The length of the string does not include the NULL character.
For binding and defining variables of type
OCIString * use the external typecode
See Also:The prototypes and descriptions for all the functions are provided in Chapter 19, "OCI Datatype Mapping and Manipulation Functions".
The following functions allow the C programmer to manipulate an instance of a string.
Table 12-5 String Functions
get allocated size of string memory in bytes
assign one string to another
assign text string to string
get pointer to string part of string
resize string memory
get string size
This example assigns a text string to a string, then gets a pointer to the string part of the string, as well as the string size, and prints it out.
Note the double indirection used in passing the
vstring1 parameter in
OCIEnv *envhp; OCIError *errhp; OCIString *vstring1 = (OCIString *)0; OCIString *vstring2 = (OCIString *)0; text c_string[20]; text *text_ptr; sword status; strcpy((char *)c_string, "hello world"); /* Assign a text string to an OCIString */ status = OCIStringAssignText(envhp, errhp, c_string, (ub4)strlen((char *)c_string),&vstring1); /* Memory for vstring1 is allocated as part of string assignment */ status = OCIStringAssignText(envhp, errhp, (text *)"hello again", (ub4)strlen("This is a longer string."),&vstring1); /* vstring1 is automatically resized to store the longer string */ /* Get a pointer to the string part of vstring1 */ text_ptr = OCIStringPtr(envhp, vstring1); /* text_ptr now points to "hello world" */ printf("%s\n", text_ptr);
Variable-length raw data is represented in C using the
OCIRaw * datatype.
For binding and defining variables of type
OCIRaw *, use the external typecode
See Also:The prototypes and descriptions for all the functions are provided in Chapter 19, "OCI Datatype Mapping and Manipulation Functions"
The following functions perform OCIRaw operations.
Table 12-6 Raw Functions
get the allocated size of raw memory in bytes
assign raw data (ub1 *) to OCIRaw *
assign one OCIRaw * to another
get pointer to raw data
resize memory of variable-length raw data
get size of raw data
In this example, a raw data block is set up and a pointer to its data is obtained.
Note the double indirection in the call to
OCIEnv *envhp; OCIError *errhp; sword status; ub1 data_block[10000]; ub4 data_block_len = 10000; OCIRaw *raw1 = (OCIRaw *) 0; ub1 *raw1_pointer; /* Set up the RAW */ /* assume 'data_block' has been initialized */ status = OCIRawAssignBytes(envhp, errhp, data_block, data_block_len, &raw1); /* Get a pointer to the data part of the RAW */ raw1_pointer = OCIRawPtr(envhp, raw1);
Oracle provides two types of collections: variable-length arrays (
varrays) and nested tables. In C applications, varrays are represented as
OCIArray *, and nested tables are represented as
OCITable *. Both of these datatypes (along with OCIColl and
OCIIter, described later) are opaque structures.
A variety of generic collection functions enable you to manipulate collection data. You can use these functions on both varrays and nested tables. In addition, there is a set of functions specific to nested tables.
See Also:"Nested Table Manipulation Functions"
You can allocate an instance of a varray or nested table using
OCIObjectNew() and free it using
See Also:The prototypes and descriptions for all the functions are provided in "OCI Collection and Iterator Functions"
Oracle provides two types of collections: variable-length arrays (varrays) and nested tables. Both varrays and nested tables can be viewed as sub-types of a generic collection type.
In C, a generic collection is represented as
OCIColl *, a varray is represented as
OCIArray *, and a nested table as
OCITable *. Oracle provides a set of functions to operate on generic collections (such as
OCIColl *). These functions start with the prefix
OCIColl, as in
OCICollGetElem(). The
OCIColl*() functions can also be called to operate on varrays and nested tables.
The generic collection functions are grouped into two main categories:
manipulating varray or nested table data
scanning through a collection with a collection iterator
The generic collection functions represent a complete set of functions for manipulating varrays. Additional functions are provided to operate specifically on nested tables. They are identified by the prefix
OCITable, as in
See Also:"Nested Table Manipulation Functions"
Note:Indexes passed to collection functions are zero-based
The following generic functions manipulate collection data:
Table 12-7 Collection Functions
append an element
assign one collection to another
assign element at given index
get pointer to an element given its index
get array of elements from a collection
Indicates whether a collection is locator-based or not
get upper bound of collection
get current size of collection
trim n elements from the end of the collection
The following generic functions enable you to scan collections with a collection iterator. The iterator is of type
OCIIter, and is created by first calling
Table 12-8 Collection Scanning Functions
create an iterator for scanning collection
delete iterator
get pointer to current element pointed by iterator
initialize iterator to scan the given collection
get pointer to next element
get pointer to previous element
This example creates and uses a collection iterator to scan through a varray.
OCIEnv *envhp; OCIError *errhp; text *text_ptr; sword status; OCIArray *clients; OCIString *client_elem; OCIIter *iterator; boolean eoc; void *elem; OCIInd *elemind; /* Assume envhp, errhp have been initialized */ /* Assume clients points to a varray */ /* Print the elements of clients */ /* To do this, create an iterator to scan the varray */ status = OCIIterCreate(envhp, errhp, clients, &iterator); /* Get the first element of the clients varray */ printf("Clients' list:\n"); status = OCIIterNext(envhp, errhp, iterator, &elem, (void **) &elemind, &eoc); while (!eoc && (status == OCI_SUCCESS)) { client_elem = *((OCIString **)elem); /* client_elem points to the string */ /* the element pointer type returned by OCIIterNext() through 'elem' is the same as that of OCICollGetElem(). Refer to OCICollGetElem() for details. */ /* client_elem points to an OCIString descriptor, so to print it out, get a pointer to where the text begins */ text_ptr = OCIStringPtr(envhp, client_elem); /* text_ptr now points to the text part of the client OCIString, which is a NULL-terminated string */ printf(" %s\n", text_ptr); status = OCIIterNext(envhp, errhp, iterator, &elem, (void **)&elemind, &eoc); } if (status != OCI_SUCCESS) { /* handle error */ } /* destroy the iterator */ status = OCIIterDelete(envhp, errhp, &iterator);
As its name implies, one table may be nested, or contained within another, as a variable, attribute, parameter or column. Nested tables may have elements deleted, by means of the
OCITableDelete() function.
For example, suppose a table is created with 10 elements, and
OCITableDelete() is used to delete elements at index 0 through 4 and 9. The first existing element is now element 5, and the last existing element is element 8.
As noted previously, the generic collection functions may be used to map to and manipulate nested tables. In addition, the following functions are specific to nested tables. They should not be used on varrays.
Table 12-9 Nested Table Functions
delete an element at a given index
test whether an element exists at a given index
return index for first existing element of table
return index for last existing element of table
return index for next existing element of table
return index for previous existing element of table
return table size, not including deleted elements
When a nested table is fetched into the object cache, its elements are given a transient ordering, numbered from zero to the number of elements, minus 1. For example, a table with 40 elements would be numbered from 0 to 39.
You can use these position ordinals to fetch and assign the values of elements (for example, fetch to element i, or assign to element j, where i and j are valid position ordinals for the given table).
When the table is copied back to the database, its transient ordering is lost. Delete operations may be performed against elements of the table. Delete operations create transient holes; that is, they do not change the position ordinals of the remaining table elements.
You can retrieve a locator to a nested table. A locator is like a handle to a collection value, and it contains information about the database snapshot which exists at the time of retrieval. This snapshot information helps the database retrieve the correct instantiation of a collection value at a later time when collection elements are fetched using the locator.
Unlike a LOB locator, a collection locator cannot be used to modify a collection instance, they merely locate the correct data. Using the locator enables an application to return a handle to a nested table without having to retrieve the entire collection, which may be quite large.
A user specifies when a table is created if a locator should be returned when a collection column or attribute is fetched, using the
LOCATOR specification.
See Also:Oracle Database SQL Language Reference for more information
You can use the
OCICollIsLocator() function to determine whether a collection is a locator.
The collection element itself can be directly or indirectly another collection type. Multilevel collection type is the name given to such a top-level collection type.
Multilevel collections have the following characteristics:
They can be collections of other collection types.
They can be collections of objects with collection attributes.
They have no limit to the number of nesting levels.
They can contain any combination of varrays and nested tables.
They can be used as columns in tables.
OCI routines work with multilevel collections. The following routines can return in parameter
*elem a
OCIColl*, which can be used in any of the collection routines:
The following functions take a collection element and add it to an existing collection. Parameter
elem could be an
OCIColl* if the element type is another collection:
Assume that the following types and tables are used for the example:
type_1 (a NUMBER, b NUMBER) NT1 TABLE OF type_1 NT2 TABLE OF NT1
The following snippet of code iterates over the multilevel collection:
... OCIColl *outer_coll; OCIColl *inner_coll; OCIIter *itr1, *itr2; Type_1 *type_1_instance; .. /* assume outer_coll points to a valid coll of type NT2 */ checkerr(errhp, OCIIterCreate(envhp, errhp, outer_coll, &itr1)); for(eoc = FALSE;!OCIIterNext(envhp, errhp, itr1, (void **) &elem, (void **) &elem_null, &eoc) && !eoc;) { inner_coll = (OCIColl *)elem; /* iterate over inner collection.. */ checkerr(errhp, OCIIterCreate(envhp, errhp, inner_coll, &itr2)); for(eoc2 = FALSE;!OCIIterNext(envhp, errhp, itr2, (void **)&elem2, (void **) &elem2_null, &eoc2) && !eoc2;) { type_1_instance = (Type_1 *)elem2; /* use the fields of type_1_instance */ } /* close iterator over inner collection */ checkerr(errhp, OCIIterDelete(envhp, errhp, &itr2)); } /* close iterator over outer collection */ checkerr(errhp, OCIIterDelete(envhp, errhp, &itr1)); ...
REF (reference) is an identifier to an object. It is an opaque structure that uniquely locates the object. An object may point to another object by way of a
In C applications, the
REF is represented by
See Also:The prototypes and descriptions for all the functions are provided in Chapter 19, "OCI Datatype Mapping and Manipulation Functions".
The following functions perform
REF operations.
Table 12-10 REF Manipulation Functions
assign one
clear or nullify a
convert hexadecimal string to a
return size of hex string representation of
compare two
test whether a
This example tests two
REFs for
NULL, compares them for equality, and assigns one
REF to another. Note the double indirection in the call to
OCIEnv *envhp; OCIError *errhp; sword status; boolean refs_equal; OCIRef *ref1, *ref2; /* assume refs have been initialized to point to valid objects */ /*Compare two REFs for equality */ refs_equal = OCIRefIsEqual(envhp, ref1, ref2); printf("After first OCIRefIsEqual:\n"); if(refs_equal) printf("REFs equal\n"); else printf("REFs not equal\n"); /*Assign ref1 to ref2 */ status = OCIRefAssign (envhp, errhp, ref1, &ref2); if(status != OCI_SUCCESS) /*error handling*/ /*Compare the two REFs again for equality */ refs_equal = OCIRefIsEqual(envhp, ref1, ref2); printf("After second OCIRefIsEqual:\n"); if(refs_equal) printf("REFs equal\n"); else printf("REFs not equal\n");
The OCI datatypes and type descriptors are discussed in this section.
When a given type is created with the
CREATE TYPE statement, it is stored in the server and associated with a type descriptor object (TDO). In addition, the database stores descriptor objects for each data attribute of the type, each method of the type, each parameter of each method, and the results returned by methods. The following table lists the OCI datatypes associated with each type of descriptor object.
Table 12-11 Descriptor Objects
|Information Type
|OCI Datatype
Type Attributes Collection Elements Method Parameters Method Results
Several OCI functions (including
OCIBindObject() and
OCIObjectNew()) require a TDO as an input parameter. An application can obtain the TDO by calling
OCITypeByName(), which gets the type's TDO in an
OCIType variable. Once you obtain the TDO, you can pass it, as necessary to other calls.
These capabilities allow you to model self-descriptive data. You can store heterogeneous datatypes in the same column and query the type of data in an application.
These definitions are used in the discussion in the following sections:
Persistent types. These are created using the SQL statement
CREATE TYPE. They are stored persistently in the database.
Transient types. Anonymous type descriptions that are not stored persistently in the database. They are created by programs on the fly. They are useful for exchanging type information, if necessary, between various components of an application in a dynamic fashion.
Self-descriptive data. Data encapsulating type information with its actual contents. The
OCIAnyData datatype models such data in OCI. A data value of most SQL types can be converted to an OCIAnyData which can then be converted back to the old data value. The type
SYS.ANYDATA models such data in SQL or PL/SQL.
Self-descriptive dataset. Encapsulation of a set of data instances (all of the same type) along with their type description. They should all have the same type description. The
OCIDataAnySet datatype models this data in OCI. The type
SYS.ANYDATASET models such data in SQL or PL/SQL.
Interfaces are available in both OCI (C language) as well as in SQL and PL/SQL for constructing and manipulating these type descriptions as well as self-descriptive data. The following sections describe the relevant OCI interfaces.
See Also:For more information see "Persistent Objects, Transient Objects, and Values", and Oracle Database SQL Language Reference, section "Oracle-Supplied Types" for an overview
The type interfaces can be used to construct named as well as anonymous transient object types (structured with attributes) and collection types. The
OCITypeBeginCreate() call is used to begin type construction of transient object types as well as collection types (the typecode parameter determines which one is being constructed).
You need to allocate a parameter handle using
OCIDescriptorAlloc(). Subsequently, type information (for attributes of an object type as well as for the collection element's type) needs to be set using
OCIAttrSet(). For object types, use
OCITypeAddAttr() to add the attribute information to the type. After information on the last attribute has been added, you must call
For example:
OCITypeBeginCreate( ...) /* Begin Type Creation */ OCIDescriptorAlloc(...) OCIAttrSet(...) OCITypeAddAttr(...) /* Add attribute 1 */ OCIAttrSet(...) OCITypeAddAttr(...) /* Add attribute 2 */ ... OCITypeEndCreate(...) /* End Type Creation */
For collection types, the information on the collection element type needs to be set with
OCITypeSetCollection(). Subsequently,
OCITypeEndCreate() is called to finish construction.
For example:
OCITypeBeginCreate( ...) /* Begin Type Creation */ OCIDescriptorAlloc(...) OCIAttrSet(...) OCITypeSetCollection(...) /* Set information on collection element */ OCITypeEndCreate(...) /* End Type Creation */
OCIDescribeAny() call can be used to obtain the
OCIType corresponding to a persistent type.
OCIDescriptorAlloc() call can be used to allocate an
OCIParam (with the parent handle being the environment handle). Subsequently,
OCIAttrSet() can be called with the following allowed attribute types to set relevant type information:
To set numeric precision. Pass a
(ub1 *) attribute value to the buffer holding precision value.
To set numeric scale. Pass a
(sb1 *) attribute value to the buffer holding scale value.
To set the character set id for character types. Pass a
(ub2 *) attribute value to the buffer holding char set id.
To set the character set form for character types. Pass a
(ub1 *) attribute value to the buffer holding character set form value.
Length of
RAW, and so on. Pass a
(ub2 *) attribute value to the buffer holding length.
To set typecode. Pass a
(ub2 *) attribute value to the buffer holding typecode. This attribute needs to be set first.
To set
OCIType of an object or collection attribute. Pass a
(OCIType *) attribute value to the
OCIType corresponding to the attribute. It is your responsibility to make sure that the
OCIType is pinned when this
OCIParam is used during
AnyType construction. If it is a transient type attribute, its allocation duration should be at least as much as the top level
OCIType being created. There will be an exception returned otherwise.
For built-in types, here are the acceptable typecodes (the permissible values for
OCI_ATTR_TYPECODE) for SQL type attributes:
If the attribute/collection element type is itself another transient type, set
OCI_ATTR_TYPECODE to:
OCI_TYPECODE_OBJECT or
OCI_TYPECODE_REF (for REFS) or
OCI_TYPECODE_VARRAY or
OCI_TYPECODE_TABLE and set the
OCI_ATTR_TDO to the
OCIType corresponding to the transient type.
For user defined type attributes, the permissible values for
OCI_ATTR_TYPECODE are:
OCI_TYPECODE_OBJECT (for an Object Type),
OCI_TYPECODE_REF (for a
REF type)
OCI_TYPECODE_VARRAY or
(for collections).
OCI_ATTR_TDO should be set in these cases to the appropriate
user-defined type's
OCIDescribeAny() call can be used to obtain the
OCIType corresponding to a persistent type. For example:
OCIDescribeAny(svchp, errhp. (void *)"HR.EMPLOYEES", (ub4)strlen("HR.EMPLOYEES"), (ub1)OCI_OTYPE_NAME, (ub1)OCI_DEFAULT, OCI_PTYPE_TYPE, dschp);
From the describe handle (
dschp), the
OCIType can be obtained using
OCIAttrGet() calls.
OCIDescribeAny() can be called with these transient type descriptions for a dynamic description of the type. The
OCIType pointer can be passed directly to
OCIDescribeAny() (with
objtype set to
OCI_OTYPE_PTR). This provides a way to obtain attribute information by name as well as position.
For transient types that represent built-in types (created with a built-in typecode), the parameter handle that describes these types (which will be of type
OCI_PTYPE_TYPE) will support the following extra attributes.
These attributes will have the usual meanings they have while describing a type attribute.
Note:These attributes are supported only for transient built-in types. The attributes
OCI_ATTR_IS_TRANSIENT_TYPE and
OCI_ATTR_IS_PREDEFINED_TYPE are true for these types. For persistent types, these attributes are supported only from the parameter handle of the type's attributes (which will be of type
OCIAnyData encapsulates type information as well as a data instance of that type (that is, self descriptive data). An
OCIAnyData can be created from any built-in or user-defined type instance using the
OCIAnyDataConvert() call. This call does a conversion (cast) to an
Alternatively, object types and collection types can be constructed piece by piece (an attribute at a time for object types or a collection element at a time). To construct in this fashion,
OCIAnyDataBeginCreate() should be called with the type information (
OCIType). Subsequently
OCIAnyDataAttrSet() can be used for object types and
OCIAnyDataCollAddElem() can be used for collection types.
OCIAnyDataEndCreate() must then be called to finish the construction process.
Subsequently, the access routines can be invoked. To convert (cast) an
OCIAnyData to the corresponding type instance, the
OCIAnyDataAccess() call can be used.
OCIAnyData that is based on an object or collection type can also be accessed piece by piece.
Special collection construction and access calls are provided for performance improvement. These calls can be used to avoid unnecessary creation and copying of the entire collection in memory. For example:
OCIAnyDataConvert(...) /* Cast a built-in or user-defined type instance to an OCIAnyData in 1 call. */ OCIAnyDataBeginCreate(...) /* Begin AnyData Creation */ OCIAnyDataAttrSet(...) /* Attribute-wise construction for object types */
OCIAnyDataCollAddElem(...) /* Element-wise construction for collections */ OCIAnyDataEndCreate(...) /* End OCIAnyData Creation */
The function
OCIAnyDataTypeCodeToSqlt() converts the
OCITypeCode for an AnyData value to the
SQLT code that corresponds to the representation of the value as returned by the
OCIAnyData API.
The following typecodes are used in the OCIAnyData functions only:
In calls to other functions, such as
OCIDescribeAny(), these typecodes are not returned and you must use the charset form to determine if the data is
NCHAR (if charset form is SQLCS_NCHAR).
OCIAnyDataTypeCodeToSqlt() converts
OCI_TYPECODE_CHAR as well as
OCI_TYPECODE_VARCHAR2 to the output values
SQLT_VST (which corresponds to the
OCIString mapping) with a charset form of
OCI_TYPECODE_NVARCHAR2 will also return
OCIString mapping is used by OCIAnyData API) with a charset form of
See Also:For more information see "OCIAnyDataTypeCodeToSqlt()"
OCIAnyDataSet encapsulates type information as well as a set of instances of that type.
OCIAnyDataSetBeginCreate() is called to begin the construction process.
OCIAnyDataSetAddInstance() is called to add a new instance and this call returns the
OCIAnyData corresponding to that instance.
Then, the OCIAnyData functions can be invoked to construct this instance.
OCIAnyDataSetEndCreate() is called once all instances have been added.
For access, call
OCIAnyDataSetGetInstance() to get the
OCIAnyData corresponding to the instance. Only sequential access is supported. Subsequently, the OCIAnyData access functions can be invoked. For example:
OCIAnyDataSetBeginCreate(...) /* Begin AnyDataSet Creation */ OCIAnyDataSetAddInstance(...) /* Add a new instance to the AnyDataSet */ /* Use the OCIAnyData*() functions to create the instance */ OCIAnyDataSetEndCreate(...) /* End OCIAnyDataSet Creation */
Note:For complete descriptions of all the calls in these interfaces, see Chapter 21, "OCI Any Type and Data Functions".
This section provides information on binding named datatypes, such as objects and collections, and
For a named datatype (object type or collection) bind, a second bind call is necessary following
OCIBindByName(), or
OCIBindByPos(). The OCI Bind Object Type call,
OCIBindObject(), sets up additional attributes specific to the object type bind. An OCI application uses this call when fetching data from a table which has a column with an object datatype.
OCIBindObject() call takes, among other parameters, a Type Descriptor Object (TDO) for the named datatype. The TDO, of datatype
OCIType is created and stored in the database when a named datatype is created. It contains information about the type and its attributes. An application can obtain a TDO by calling
OCIBindObject() call also sets up the indicator variable or structure for the named datatype bind.
When binding a named datatype, use the
SQLT_NTY datatype constant to indicate the datatype of program variable being bound.
SQLT_NTY indicates that a C struct representing the named datatype is being bound. A pointer to this structure is passed to the bind call.
With inheritance and instance substitutability, you can bind a subtype instance where the supertype is expected.
It is possible that working with named datatypes may require the use of three bind calls in some circumstances. For example, to bind a static array of named datatypes to a PL/SQL table, three calls must be invoked:
OCIBindArrayOfStruct(), and
See Also:
For information about using these datatypes to fetch an embedded object from the database, refer to the section "Fetching Embedded Objects".
For additional important information, see the section "Information for Named Datatype and REF Binds"
For more information about descriptor objects, see "Descriptor Objects".
As with named datatypes, binding
REFs is a two-step process. First, call
OCIBindByName() or
OCIBindByPos(), and then call
REFs are bound using the
SQLT_REF datatype. When
SQLT_REF is used, then the program variable being bound must be of type
OCIRef *.
With inheritance and
REF substitutability, you can bind a
REF value to a subtype instance where a
REF to the supertype is expected.
See Also:
For information about binding and pinning
REFs to objects, see "Retrieving an Object Reference from the Server".
For additional important information, see the section "Information for Named Datatype and REF Binds".
This section presents some additional important information to keep in mind when working with named datatype and
REF binds. It includes pointers about memory allocation and indicator variable usage.
If the datatype being bound is
SQLT_NTY, the indicator struct parameter of the
OCIBindObject() call (
void ** indpp) is used, and the scalar indicator is completely ignored.
If the datatype is
SQLT_REF, the scalar indicator is used, and the indicator struct parameter of
OCIBindObject() is completely ignored.
The use of indicator structures is optional. The user can pass a
NULL pointer in the
indpp parameter for the
OCIBindObject() call. During the bind, this means that the object is not atomically
NULL and none of its attributes are
The indicator struct size pointer,
indsp, and program variable size pointer,
pgvsp, in the
OCIBindObject() call is optional. Users can pass
NULL if these parameters are not needed.
For doing array binds of named datatypes or
REFs, for array inserts or fetches, the user needs to pass in an array of pointers to buffers (preallocated or otherwise) of the appropriate type. Similarly, an array of scalar indicators for
SQLT_REF types or an array of pointers to indicator structs for
SQLT_NTY types needs to be passed.
See Also:For more information about
SQLT_NTY, see the section "Named Datatypes: Object, VARRAY, Nested Table".
This section provides information on defining named datatypes (for example, objects, collections) and
For a named datatype (object type, nested table, varray) define, two define calls are necessary. The application should first call
OCIDefineByPos(), specifying
SQLT_NTY in the
dty parameter. Following
OCIDefineByPos(), the application must call
OCIDefineObject(). In this case, the data buffer pointer in
OCIDefineByPos() is ignored and additional attributes pertaining to a named datatype define are set up using the OCI Define Object attributes call,
SQLT_NTY datatype constant is specified for a named datatype define. In this case, the application fetches the result data into a host-language representation of the named datatype. In most cases, this will be a C struct generated by the Object Type Translator.
When making an
OCIDefineObject() call, a pointer to the address of the C struct (preallocated or otherwise) must be provided. The object may have been created with
OCIObjectNew(), allocated in the cache, or with user-allocated memory.
However, in the presence of inheritance, we strongly recommend using objects in the object cache and not passing objects allocated out of user memory from the stack. The reason is that due to instance substitutability, the server may send back a subtype instance when the client is expecting a supertype instance. This requires the server to dynamically re-size the object -- which is possible only for objects in the cache.
See Also:"Information for Named Datatype and REF Defines, and PL/SQL OUT Binds" for more important information about defining named datatypes
As with named datatypes, defining for a
REF output variable is a two-step process. The first step is a call to
OCIDefineByPos(), and the second is a call to
OCIDefineObject(). Also as with named datatypes, the
SQLT_REF datatype constant is passed to the
dty parameter of
SQLT_REF indicates that the application will be fetching the result data into a variable of type
OCIRef *. This
REF can then be used as part of object pinning and navigation, as described in Chapter 6.
See Also:"Information for Named Datatype and REF Defines, and PL/SQL OUT Binds" for more important information about defining
This section presents some additional important information to keep in mind when working with named datatype and
REF defines. It includes pointers about memory allocation and indicator variable usage.
A PL/SQL OUT bind refers to binding a placeholder to an output variable in a PL/SQL block. Unlike a SQL statement, where output buffers are set up with define calls, in a PL/SQL block, output buffers are set up with bind calls. Refer to the section "Binding Placeholders in PL/SQL" for more information.
If the datatype being defined is
SQLT_NTY, the indicator struct parameter of the
OCIDefineObject() call (
void ** indpp) is used, and the scalar indicator is completely ignored.
If the datatype is
SQLT_REF, the scalar indicator is used, and the indicator struct parameter of
OCIDefineObject() is completely ignored.
The use of indicator structures is optional. The user can pass a
NULL pointer in the
indpp parameter for the
OCIDefineObject() call. During a fetch or PL/SQL OUT bind, this means that the user is not interested in any information about being null.
In a SQL define or PL/SQL OUT bind, you can pass in preallocated memory for either the output variable or the indicator. Then that preallocated memory is used to store result data, and all secondary memory (out-of-line memory), if any, will be deallocated. The preallocated memory must come from the cache (the result of an
OCIObjectNew() call).
Note:If a client application wants to allocate memory from its own private memory space, instead of the cache, it must insure that there is no secondary out-of-line memory in the object.
For an object define with type
SQLT_NTY, client applications wanting to preallocate object memory must use the
OCIObjectNew() function. Client applications should not allocate the object in its own private memory space, such as with
malloc() or on the stack. The
OCIObjectNew() function allocates the object in the object cache. The allocated object can be freed using
OCIObjectFree(). Refer to Chapter 18, "OCI Navigational and Type Functions" for details on
OCIObjectNew() and
Note:There is no change to the behavior of
OCIDefineObject() when the user does not preallocate the object memory and instead initializes the output variable to null pointer value. In this case, the object will be implicitly allocated in the object cache by the OCI library.
In a SQL define or PL/SQL OUT bind, if the user passes in a
NULL address for the output variable or the indicator, memory for the variable or the indicator will be implicitly allocated by OCI.
If an output object of type
SQLT_NTY is atomically
NULL (in a SQL define or PL/SQL OUT bind), only the
NULL indicator struct will get allocated (implicitly if necessary) and populated accordingly to indicate the atomic nullity of the object. The top-level object, itself, will not get implicitly allocated.
An application can free indicators by calling
OCIObjectFree(). If there is a top-level object (as in the case of a non-atomically
NULL object), then the indicator is freed when the top-level object is freed with
OCIObjectFree(). If the object is atomically null, then there is no top-level object, so the indicator must be freed separately.
The indicator struct size pointer,
indsp, and program variable size pointer,
pgvsp, in the
OCIDefineObject() call is optional. Users can pass
NULL if these parameters are not needed.
For doing array defines of named datatypes or
REFs, the user needs to pass in an array of pointers to buffers (preallocated or otherwise) of the appropriate type. Similarly, an array of scalar indicators (for
SQLT_REF types) or an array of pointers to indicator structs (for
SQLT_NTY types) needs to be passed.
Previous chapters of this book have discussed OCI bind and define operations. "Binding Placeholders in OCI" discussed the basics of OCI bind operations, while "Defining Output Variables in OCI" discusses the basics of OCI define operations. Information specific to binding and defining named datatypes and
REFs is found in Chapter 5, "Binding and Defining in OCI".
The sections covering basic bind and define functionality showed how an application could use a scalar variable or array of scalars as an input (bind) value in a SQL statement, or as an output (define) buffer for a query.
The sections covering named datatypes and
REFs showed how to bind or define an object or reference. Chapter 11, "OCI Object-Relational Programming" expanded on this to talk about pinning object references, object navigation, and fetching embedded instances.
The purpose of this section is to cover binding and defining of individual attribute values, using the datatype mappings explained in this chapter.
Variables of one of the types defined in this chapter, such as
OCINumber or
OCIString, can typically be declared in an application and used directly in an OCI bind or define operation as long as the appropriate datatype code is specified. The following table lists the datatypes that can be used for binds and defines, along with their C mapping, and the OCI external datatype which must be specified in the dty (datatype code) parameter of the bind or define call.
Table 12-12 Datatype Mappings for Binds and Defines
|C Mapping
|OCI External Datatype and Code
OCILobLocator *
CILobLocator *
OCIString *
SQLT_VST (see note following)
OCIRaw *
SQLT_LVB (see note following)
OCIString *
struct *
Named Datatype (SQLT_NTY)
OCIRef *
OCIArray *
Named Datatype (SQLT_NTY)
Nested Table
OCITable *
Named Datatype (SQLT_NTY)
OCIDateTime *
OCIInterval *
Note:Before fetching data into a define variable of type
OCIString *, the size of the string must first be set using the
OCIStringResize() routine. This may require a describe operation to obtain the length of the select-list data. Similarly, an
OCIRaw * must be first sized with
The following section presents examples of how to use C-mapped datatypes in an OCI application.
See Also:For a discussion of OCI external datatypes, and a list of datatype codes, refer to Chapter 3, "Datatypes".
The examples in this section demonstrate how variables of type
OCINumber can be used in OCI bind and define operations.
Assume, for this example, that the following
person object type was created:
CREATE TYPE person AS OBJECT (name varchar2(30), salary number);
This type is then used to create an
employees table which has a column of type
CREATE TABLE employees (emp_id number, job_title varchar2(30), emp person);
The Object Type Translator (OTT) generates the following C struct and null indicator struct for
struct person { OCIString * name; OCINumber salary;}; typedef struct person person; struct person_ind { OCIInd _atomic; OCIInd name; OCIInd salary;} typedef struct person_ind person_ind;
See Also:For a complete discussion of OTT, see Chapter 15, "Using the Object Type Translator with OCI"
Assume that the
employees table has been populated with values, and an OCI application has declared a
person variable:
person *my_person;
and fetched an object into that variable through a
SELECT statement, like
text *mystmt = (text *) "SELECT person FROM employees WHERE emp.name='Andrea'";
This would require defining
my_person to be the output variable for this statement, using appropriate OCI define calls for named datatypes, as described in the section "Advanced Define Operations in OCI". Executing the statement would retrieve the
person object named
Andrea into the
my_person variable.
Once the object is retrieved into
my_person, the OCI application now has access to the attributes of
my_person, including the name and the salary.
The application could go on to update another employee's salary to be the same as Andrea's, as in
text *updstmt = (text *) "UPDATE employees SET emp.salary = :newsal WHERE emp.name = 'MONGO'";
Andrea's salary (stored in
my_person->salary) would be bound to the placeholder
:newsal, specifying an external datatype of
VARNUM (datatype code=6) in the bind operation:
OCIBindByName(...,":newsal",...,&my_person->salary,...,6,...); OCIStmtExecute(...,updstmt,...);
Executing the statement updates Mongo's salary in the database to be equal to Andrea's, as stored in
Conversely, the application could update Andrea's salary to be the same as Mongo's, by querying the database for Mongo's salary, and then making the necessary salary assignment:
text *selstmt = (text *) "SELECT emp.salary FROM employees WHERE emp.name = 'MONGO'"; OCINumber mongo_sal; ... OCIDefineByPos(...,1,...,&mongo_sal,...,6,...); OCIStmtExecute(...,selstmt,...); OCINumberAssign(...,&mongo_sal, &my_person->salary);
In this case, the application declares an output variable of type
OCINumber and uses it in the define step. In this case we define an output variable for position 1, and use the appropriate datatype code (6 for
The salary value is fetched into the
OCINumber, and the appropriate OCI function,
OCINumberAssign(), is used to assign the new salary to the copy of the Andrea object currently in the cache. To modify the data in the database, the change must be flushed to the server.
The examples in the previous section should give some idea of the flexibility which the Oracle datatypes provide for bind and define operations. The goal of this section is to show how the same operation can be performed in several different ways. The goal is to give you some idea of the variety of ways in which these datatypes can be used in OCI applications.
The examples in this section are intended to demonstrate the flow of calls used to perform certain OCI tasks. An expanded pseudocode is used for the examples in this section. Actual function names are used, but for the sake of simplicity not all parameters and typecasts are filled in. Additionally, other necessary OCI calls, like handle allocations, have been omitted.
The scenario for these examples is as follows:
An employee named
BRUCE exists in the
employees table for a hospital. See
person type and
employees table creation statements in the previous section.
Bruce's current job title is
Bruce is being promoted to
RADIOLOGY_CHIEF, and along with the promotion comes a salary increase.
Hospital salaries are in whole dollar values, are set according to job title, and stored in a table called
salaries, defined as follows:
CREATE TABLE salaries (job_title varchar2(20), salary integer));
Bruce's salary needs to be updated to reflect his promotion.
Accomplishing the preceding task requires that the application retrieve the salary corresponding to
RADIOLOGY_CHIEF from the
salaries table, and update Bruce's salary. A separate step would write his new title and the modified object back to the database.
Assuming that a variable of type
person has been declared
person * my_person;
and the object corresponding to Bruce has been fetched into it, the following sections present three different ways in which the salary update could be performed.
This example uses the following method:
Do a traditional OCI define using an integer variable to retrieve the new salary from the database.
Convert the integer to an
Assign the new salary to Bruce.
#define INT_TYPE 3 /* datatype code for sword integer define */ text *getsal = (text *) "SELECT salary FROM salaries WHERE job_title='RADIOLOGY_CHIEF'"; sword new_sal; OCINumber orl_new_sal; ... OCIDefineByPos(...,1,...,new_sal,...,INT_TYPE,...); /* define int output */ OCIStmtExecute(...,getsal,...); /* get new salary as int */ OCINumberFromInt(...,new_sal,...,&orl_new_sal); /* convert salary to OCINumber */ OCINumberAssign(...,&orl_new_sal, &my_person->salary); /* assign new salary */
This method eliminates one of the steps in Method 1:
Define an output variable of type
OCINumber, so that no conversion is necessary after the value is retrieved.
Assign the new salary to Bruce
#define VARNUM_TYPE 6 /* datatype code for defining VARNUM */ text *getsal = (text *) "SELECT salary FROM salaries WHERE job_title='RADIOLOGY_CHIEF'"; OCINumber orl_new_sal; ... OCIDefineByPos(...,1,...,orl_new_sal,...,VARNUM_TYPE,...); /* define OCINumber output */ OCIStmtExecute(...,getsal,...); /* get new salary as OCINumber */ OCINumberAssign(...,&orl_new_sal, &my_person->salary); /* assign new salary */
This method accomplishes the entire operation with a single define and fetch. No intervening output variable is used, and the value retrieved from the database is fetched directly into the salary attribute of the object stored in the cache.
Since Bruce is pinned in the object cache, use the location of his salary attribute as the define variable, and execute/fetch directly into it.
#define VARNUM_TYPE 6 /* datatype code for defining VARNUM */ text *getsal = (text *) "SELECT salary FROM salaries WHERE job_title='RADIOLOGY_CHIEF'"; ... OCIDefineByPos(...,1,...,&my_person->salary,...,VARNUM_TYPE,...); /* define bruce's salary in cache as output variable */ OCIStmtExecute(...,getsal,...); /* execute and fetch directly */
As the previous three examples show, the C datatypes provide flexibility for binding and defining. In these examples an integer can be fetched, and then converted to an
OCINumber for manipulation. An
OCINumber can be used as an intermediate variable to store the results of a query. Or, data can be fetched directly into a desired
OCINumber attribute of an object.
Note:In all of these examples it is important to keep in mind that in OCI, if an output variable is defined before the execution of a query, the resulting data will be prefetched directly into the output buffer.
In the preceding examples, extra steps would be necessary to insure that changes are written to the database permanently. This may involve SQL
UPDATE calls and OCI transaction commit calls.
These examples all dealt with define operations, but a similar situation applies for binding.
Similarly, although these examples dealt exclusively with the
OCINumber type, a similar variety of operations are possible for the other Oracle C types described in the remainder of this chapter.
The following code fragments demonstrate the use of SQLT_NTY bind and define calls, including
OCIBindObject() and
OCIDefineObject(). In each example, a previously defined SQL statement is being processed.
/* ** This example performs a SQL insert statement */ void insert(envhp, svchp, stmthp, errhp, insstmt, nrows) OCIEnv *envhp; OCISvcCtx *svchp; OCIStmt *stmthp; OCIError *errhp; text *insstmt; ub2 nrows; { OCIType *addr_tdo = (OCIType *)0 ; address addrs; null_address naddrs; address *addr = &addrs; null_address *naddr = &naddrs; sword custno =300; OCIBind *bnd1p, *bnd2p; ub2 i; /* define the application request */ checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) insstmt, (ub4) strlen((char *)insstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); /* bind the input variable */ checkerr(errhp, OCIBindByName(stmthp, &bnd1p, errhp, (text *) ":custno", (sb4) -1, (void *) &custno, (sb4) sizeof(sword), SQLT_INT, (void *) 0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); checkerr(errhp, OCIBindByName(stmthp, &bnd2p, errhp, (text *) ":addr", (sb4) -1, (void *) 0, (sb4) 0, SQLT_NTY, (void *) 0, (ub2 *)0, (ub2 *)0, (ub4) 0, (ub4 *) 0, (ub4) OCI_DEFAULT)); checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) SCHEMA, (ub4) strlen((char *)SCHEMA), (const text *)"ADDRESS_VALUE", (ub4) strlen((char *)"ADDRESS_VALUE"), (text *)0, 0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, &addr_tdo)); if(!addr_tdo) { printf("Null tdo returned\n"); return; } checkerr(errhp, OCIBindObject(bnd2p, errhp, addr_tdo, (void **) &addr, (ub4 *) 0, (void **) &naddr, (ub4 *) 0));
/* ** This example executes a SELECT statement from a table which includes ** an object. */ void selectval(envhp, svchp, stmthp, errhp) OCIEnv *envhp; OCISvcCtx *svchp; OCIStmt *stmthp; OCIError *errhp; { OCIType *addr_tdo = (OCIType *)0; OCIDefine *defn1p, *defn2p; address *addr = (address *)NULL; sword custno =0; sb4 status; /* define the application request */ checkerr(errhp, OCIStmtPrepare(stmthp, errhp, (text *) selvalstmt, (ub4) strlen((char *)selvalstmt), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); /* define the output variable */ checkerr(errhp, OCIDefineByPos(stmthp, &defn1p, errhp, (ub4) 1, (void *) &custno, (sb4) sizeof(sword), SQLT_INT, (void *) 0, (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)); checkerr(errhp, OCIDefineByPos(stmthp, &defn2p, errhp, (ub4) 2, (void *) 0, (sb4) 0, SQLT_NTY, (void *) 0, (ub2 *)0, (ub2 *)0, (ub4) OCI_DEFAULT)); checkerr(errhp, OCITypeByName(envhp, errhp, svchp, (const text *) SCHEMA, (ub4) strlen((char *)SCHEMA), (const text *) "ADDRESS_VALUE", (ub4) strlen((char *)"ADDRESS_VALUE"), (text *)0, 0, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, &addr_tdo)); if(!addr_tdo) { printf("NULL tdo returned\n"); return; } checkerr(errhp, OCIDefineObject(defn2p, errhp, addr_tdo, (void **) &addr, (ub4 *) 0, (void **) 0, (ub4 *) 0)); checkerr(errhp, OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (OCISnapshot *) NULL, (OCISnapshot *) NULL, (ub4) OCI_DEFAULT));


text:
Two months after an ex-manager sued her for $100 million claiming breach of oral contract, Bethenny Frankel is speaking out about the "frivolous" lawsuit.
During a recent visit to Canada to promote her Skinnygirl drink line, the Bethenny Ever After star gave an interview to the Globe and Mail during which she displayed her trademark brutal honesty. "That doesn't bother me," she retorts when asked about the lawsuit. "That's frivolous and I would spend $20-million to punish him for wasting my time, the legal system's time and that bag of bullshit. I will send back all the purses and all the diamonds and everything to sue that guy's ass and put him where he belongs."
And when it comes to her Bravo reality show, Bethenny was asked if there's a part of her people do not get to see on the show. "I get very moody and grouchy," she admits. "Sometimes, I'm from a place of no." You don't say Bethenny?
When asked what her estranged mother Bernadette Parisella Birk would think of her mega success (she sold her drink line for a reported $120 million), Bethenny replies, "I don't know what she makes of my success." She continues, "I'm sure it's quite shocking and overwhelming to her," adding she hasn't talked to her "in years."
As in past interviews, Bethenny once again reiterated her plans to leave the world of reality television sooner than later. "We won't be doing this for much longer at all," she declares. "I don't want to be on reality TV that much."
And what is Bethenny's advice to her fans who would like to be in her shoes? "I have always believed in myself," she states about her work ethic. "You treat every job as if it's the most important job, and you will end up where I have ended up."
Meanwhile ABC announced that Bethenny will return to The View talk show on Tuesday, July 12 as a guest co-host.
The isn't Bethenny's first time on the show as she also co-hosted last summer during which she got into a minor disagreement with Joy Behar over breast feeding. After Bethenny complained that that breastfeeding can be "the hardest thing in the whole world," Joy stated, "I didn't find it hard at all" and that Bethenny "shouldn't tell women" it's difficult.


text:
Teen Cooking Show Teaches Culture, Cameras And Chopping Skills
"So directors, in order to get something going, you say 'quiet on the set,'" Kristine Diekman shouts across the room to the two high school girls poring over a script. Diekman is a professor of video and new media at Cal State San Marcos.
Mics and cameras are in place; mixing bowls and perfectly-measured ingredients neatly laid out. This group is ready to film a high school cooking show.
"Sweet potato pie, scene six take one," says Jesse Avilez, a ninth grader at Crawford High School, clapping his slate and then walking off the set.
The actors address the camera:
"Today we're making a sweet potato and apple pie, which is our version of a traditional soul food dessert. So Dominique, can you tell us what soul food is?"
The show is called Cooking It Up. It lives as a series of webisodes along with recipes and personal stories behind those recipes.
Diekman directs the program. Her college students serve as mentors and tech support on the show.
For the Crawford High School students who participate, it is an internship where they learn video production, graphic design, nutrition and, of course, cooking.
"A lot of them just wanted to learn how to cook," Diekman said. "So many of them come from families, very busy families and they are responsible for cooking nutritious foods within their homes."
The students wanted to learn cooking basics, Diekman said, like how to chop an onion, how to handle and store food safely, and how to make it good for you.
Crystal Gillespie, an eleventh grader at Crawford High, co-directed the sweet potato pie episode.
"I cook a lot at home and, you know, my grandmother runs a daycare so the idea of finding healthy ways to make snacks was really great 'cause then it's something else I can do for the kids that's interesting," she said.
The students take turns working in different roles in show production: directing, manning the cameras and microphones, and for the brave ones, trying out their best Emeril or "Iron Chef" in front of the camera.
Some of the students are from families who've recently arrived as immigrants and refugees. They bring traditional recipes and cooking smarts to the show. And something else: a deep connection to food, through family hardships and joys.
One of the students, Nathan Yau, got the papaya salad recipe from his grandparents, who lived in Cambodia during the bloody rule of the Khmer Rouge. Nathan tells their story on the Cooking It Up website.
"Their long, long friend, he became a monk because his parents were killed during that regime. ... And he really liked papaya salad, so then they just decided to start always bringing papaya salad to him because he didn't really have nobody, except for us."
And another thing students from immigrant families bring: generally good eating habits. Researchers have found that immigrants tend to be in better shape when they arrive in the U.S. than Americans. It's known as the "healthy immigrant effect."
"Healthy eating practices are still alive here but as the youth become more and more acculturated," said Diekman, "and I can see it with this group of youth. They're starting to eat more junk food."
This is the time to encourage them to carry on their kitchen traditions and learn from each other, Diekman said.
In one episode, Avilez, the ninth grader, shows his classmates how to make and eat ceviche — hardly a standard American teenage meal.
The skills these high schoolers are learning — like motion graphics and video editing — could lead to jobs in the digital world. Or, take Avilez, the ceviche master. He actually thinks he might want to become a chef, so he appreciates the kitchen skills he's picked up.
"Like, you know, the putting your fingers back so you won't chop off your finger and you know accidentally miss a finger for, probably forever," Avilez said, demonstrating the technique.
In this fast food world, just getting young people interested in cooking seems like a small victory. In any case, it's probably better than sitting in the classroom.
"You get to cook, and then you get to eat what you cook. I mean, who doesn't love that?" Avilez said.